Found while landing #12342 (PR #12387), which had to establish what
error.code can actually hold before writing a narrowing for it.
The gap
content/docs/api/client-sdk.mdx has an Error Codes table listing nine
codes: VALIDATION_ERROR, INVALID_QUERY, UNAUTHENTICATED,
PERMISSION_DENIED, RESOURCE_NOT_FOUND, RATE_LIMIT_EXCEEDED,
INTERNAL_ERROR, SERVICE_UNAVAILABLE, NOT_IMPLEMENTED. Every one is a
member of StandardErrorCode (packages/spec/src/api/errors.zod.ts).
VALIDATION_FAILED is not in the table. It is also not in StandardErrorCode
— it is registered in ERROR_CODE_LEDGER
(packages/spec/src/api/error-code-ledger.zod.ts), so
ErrorCode.parse('VALIDATION_FAILED') succeeds and it is a real, live wire
value. Producers emit it from packages/rest (error-response.ts,
rest-server.ts, import-runner.ts) and packages/objectql
(record-validator.ts), and packages/types/src/validation-failure.ts is built
around it.
And it is the code both of the page's own error-handling examples use — one
in a trailing comment, one in a live if (error.code === 'VALIDATION_FAILED')
branch, immediately above the table that does not list it.
Why it matters
A reader who works from the table concludes a per-field validation failure
arrives as VALIDATION_ERROR and writes that branch. It never matches. The
examples are right and the table is incomplete, which is the worse way round:
the table is the part that reads like a reference.
The table also has no column or note distinguishing the closed
StandardErrorCode catalog from the ledger-registered codes, so there is no
place for a reader to learn that the vocabulary is a union of two sets. That is
arguably the real fix rather than adding one row.
Open question for triage
Whether the page should list the ledger codes at all, or state the union and
point at the spec as the authority, is a docs-shape decision — a full ledger
dump on this page would be large and would need to stay in sync. Filed as a
finding rather than a fix so triage can rule on which.
Not in scope
The narrowing defect on the same page's examples (#12342, landed as PR #12387)
and the third unnarrowed catch block (#12388) are separate; this card is only
about the code vocabulary the table publishes.
Found while landing #12342 (PR #12387), which had to establish what
error.codecan actually hold before writing a narrowing for it.The gap
content/docs/api/client-sdk.mdxhas an Error Codes table listing ninecodes:
VALIDATION_ERROR,INVALID_QUERY,UNAUTHENTICATED,PERMISSION_DENIED,RESOURCE_NOT_FOUND,RATE_LIMIT_EXCEEDED,INTERNAL_ERROR,SERVICE_UNAVAILABLE,NOT_IMPLEMENTED. Every one is amember of
StandardErrorCode(packages/spec/src/api/errors.zod.ts).VALIDATION_FAILEDis not in the table. It is also not inStandardErrorCode— it is registered in
ERROR_CODE_LEDGER(
packages/spec/src/api/error-code-ledger.zod.ts), soErrorCode.parse('VALIDATION_FAILED')succeeds and it is a real, live wirevalue. Producers emit it from
packages/rest(error-response.ts,rest-server.ts,import-runner.ts) andpackages/objectql(
record-validator.ts), andpackages/types/src/validation-failure.tsis builtaround it.
And it is the code both of the page's own error-handling examples use — one
in a trailing comment, one in a live
if (error.code === 'VALIDATION_FAILED')branch, immediately above the table that does not list it.
Why it matters
A reader who works from the table concludes a per-field validation failure
arrives as
VALIDATION_ERRORand writes that branch. It never matches. Theexamples are right and the table is incomplete, which is the worse way round:
the table is the part that reads like a reference.
The table also has no column or note distinguishing the closed
StandardErrorCodecatalog from the ledger-registered codes, so there is noplace for a reader to learn that the vocabulary is a union of two sets. That is
arguably the real fix rather than adding one row.
Open question for triage
Whether the page should list the ledger codes at all, or state the union and
point at the spec as the authority, is a docs-shape decision — a full ledger
dump on this page would be large and would need to stay in sync. Filed as a
finding rather than a fix so triage can rule on which.
Not in scope
The narrowing defect on the same page's examples (#12342, landed as PR #12387)
and the third unnarrowed
catchblock (#12388) are separate; this card is onlyabout the code vocabulary the table publishes.