Repository navigation
Two error-code vocabularies are both live: StandardErrorCode is lowercase snake_case, the servers emit SCREAMING_SNAKE #3841
Description
Activity
- added a commit that references this issue
on Jul 30, 2026 给 batch-1 实现者的交接核对点(来自 batch 3 / #3971,已先行合并)
ADR-0112 的 batch 3(dispatcher 位置收敛)在 batch 1 之前落地了。#3971 原样搬运既有 code、未定任何拼法,但有四处请在 batch-1 PR 里核对:
- 两处 fix(runtime,spec)!: the dispatcher's
error.codeis the semantic string; the HTTP status moves tohttpStatus(#3842) #3971 引入的小写:packages/spec/src/api/errors.zod.ts里HttpStatusErrorCodeMap的 13 个派生值,和新增成员method_not_allowed/precondition_required。D2 重命名 enum 时 TypeScript 会自动点名这一个文件——确认一并扫到即可。 - D7 生成
error-catalog.mdx时别丢手写内容:fix(runtime,spec)!: the dispatcher'serror.codeis the semantic string; the HTTP status moves tohttpStatus(#3842) #3971 手写了 "Request Errors (405/428)" 小节(405/428 的 dispatcher 语义、Allowheader 行为)。若生成器只从 enum + ledger 出发,这段没有结构化来源,会被覆盖蒸发——请给它一个去处(ledger 的描述字段,或生成器模板)。 content/docs/releases/v17.mdx含403 → permission_denied字样,重命名后即过时;对packages/的 harvest 大概率不扫 releases 文档。DispatcherErrorCode(runtime)可就势收敛:其四个成员中METHOD_NOT_ALLOWED/NOT_IMPLEMENTED/SERVICE_UNAVAILABLE三个在重命名后与标准目录拼写完全重合,可考虑并入;只剩ROUTE_NOT_FOUND需判归属(独立注册 vs 与ENDPOINT_NOT_FOUND合一)。
另,D5 的 client 三位置 probe 请勿在 batch 1 顺手删除:#3971 有意保留了它(版本偏斜——新 SDK 连老 server 仍需在旧位置找到 code),与 ADR「batch 3 后即删」存在一处已上报的分歧,待维护者裁决后再动。
Generated by Claude Code
- 两处 fix(runtime,spec)!: the dispatcher's
- added a commit that references this issue
on Jul 30, 2026 Status after #3988 (batch 1, merged): the decision is settled and enforced — option 1 (SCREAMING_SNAKE) per ADR-0112,
StandardErrorCoderenamed in place,ApiErrorSchema.codetightened fromz.string()to the closed setErrorCode=StandardErrorCode∪ERROR_CODE_LEDGER, catalog docs rewritten and drift-locked by test. The guard note played out as predicted: the #3687/#3837 conformance suites picked up the value check with zero test changes.Remaining work is tracked in follow-ups, so this issue stays closed:
- ADR-0112 batch 2: sweep the ~100 lowercase snake_case error-code emitters to the SCREAMING catalog #4003 — batch 2: sweep the ~100 lowercase emitters to the catalog, deleting their lowercase ledger exemptions per package until the set is fully SCREAMING.
- ADR-0112 batch 3: retire the legacy error-shape compatibility layer (error.type, client multi-location probe, enum twins) #4004 — batch 3: retire the legacy-shape compatibility layer (
error.typecarriers, the client's multi-location code probe,category/retryablenesting reads, connector enum twins). After batch 2. - Field-level error codes are four vocabularies with no schema — needs its own catalog (ADR-0112 D6 follow-up) #3977 — field-level vocabulary:
FieldErrorSchema.codewas deliberately widened toz.string()(ADR-0112 D6); its own catalog is that issue's scope.
Generated by Claude Code
- added 5 commits that reference this issue
on Jul 30, 2026
Noted as "Related, not the same" in #3689 and carried out of it when #3837 landed, so it is filed here rather than left buried in a closed issue. This one is a spec decision, not a bug fix, and it should be settled before #3689's other sibling (
error.codeoccupied by the HTTP status) is touched — otherwise that fix has no vocabulary to migrate to and would have to be redone.The drift
packages/spec/src/api/errors.zod.tsdeclaresStandardErrorCodeas a closed enum of lowercase snake_case codes:It is the declared type of
FieldErrorSchema.codeandEnhancedApiErrorSchema.code, andcontent/docs/api/error-catalog.mdxdocuments it as the catalog.Meanwhile the wire is majority SCREAMING_SNAKE. Counting distinct literals in non-test source under
packages/:AUTH_REQUIRED,FILE_NOT_FOUND,INVALID_REQUEST,PERMISSION_DENIED,ATTACHMENT_DOWNLOAD_DENIED,UPLOAD_SESSION_NOT_FOUNDvalidation_error,forbidden,bad_request,driver_missing,checksum_drift(The lowercase count includes a handful of false positives —
code: 'custom',code: 'finance'— but the shape of the split is not in doubt.)The split runs through a single request path.
http-dispatcher.ts:1379parks{ code: 'PERMISSION_DENIED' }— SCREAMING — indetails, while the enum that names the same condition calls itpermission_denied. NeitherApiErrorSchema.codenor the routes referenceStandardErrorCodeat all:ApiErrorSchemadeclares a barez.string(), so nothing is validated and both dialects pass.Why it matters now, not before
#3687 (for #3675) and #3837 (for #3689) moved the storage and i18n services into the declared envelope without reconciling the vocabulary — deliberately, because the envelope was mechanical and this is not. With the envelope settled on both paths, the code field is the remaining unenforced part of
ApiErrorSchema, and it is the part consumers actually branch on: the console's attachment panel mapsATTACHMENT_DOWNLOAD_DENIED/AUTH_REQUIREDto user-facing copy, and the dogfood suite asserts on them.What needs deciding
error-catalog.mdx. Matches what 139 codes already emit and what every consumer already reads, so no runtime migration. ButStandardErrorCodeis an exported spec type, so this is a breaking rename for anyone importing it, and the ~100 lowercase emitters still need a sweep.snake_case-for-data-values convention (Prime Directive Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3), but it changes strings the console and the dogfood suite branch on, so it needs the consumers in hand.StandardErrorCodestays the field-level validation vocabulary (FieldErrorSchema), and top-levelerror.codegets its own declared enum in the other dialect. Honest about current usage; costs one more concept.Recommendation: option 1, on the grounds that the wire is the harder thing to move and 139 > 100. Whichever wins,
ApiErrorSchema.codeshould stop beingz.string()and start referencing the chosen enum — otherwise this reopens the first time someone types a new code, and the conformance suites added in #3687/#3837 have nothing to assert the value against, only the shape.Guard note
error-envelope.conformance.test.tsandsuccess-envelope.conformance.test.ts(service-storage, service-i18n) already drive every branch and parse against the imported spec schemas. Oncecodeis a real enum they get the value check for free — the schema tightens, the suites do not change.