Skip to content

feat(errors): canonical code -> HTTP status resolver, loud on unmapped codes - #1643

Merged
pyramation merged 1 commit into
mainfrom
feat/error-http-status
Aug 3, 2026
Merged

feat(errors): canonical code -> HTTP status resolver, loud on unmapped codes#1643
pyramation merged 1 commit into
mainfrom
feat/error-http-status

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

constructive-planning#1415 reported that every HTTP surface keeps its own error-code → status table, so ACCOUNT_DISABLED is a 403 in one place and a 500 in another. The mapping already existed — every registry entry carries http — so the actual defect is narrower and worse: a code that never reached the registry answers 500 with no signal, which is indistinguishable from a crash.

Two changes:

1. One resolver, and unmapped is loud (src/http.ts):

httpStatusFor('ACCOUNT_DISABLED') // { status: 403, mapped: true }
httpStatusFor('BRAND_NEW_CODE')   // { status: 500, mapped: false } + one report per code
setUnmappedStatusReporter(code => log.warn({ code }, '...')) // default: console.warn once

toError() routes its fallback through it, so the transport path reports too:

-    http: def?.http ?? 500,
+    http: def ? def.http : httpStatusFor(code).status,

2. The registry was 3 days stale, which is how the gap got reported. Re-running the audit against constructive-db@main found 15 codes raised there that the registry doesn't knowSUBDOMAIN_APEX_NOT_PUBLISHED, APP_INSTALL_NO_SERVICE, STATIC_SITES_LIMIT, DATABASE_CLAIM_REQUIRED, the DATA_HISTORY_* family, … — every one of them a silent 500 today. Refreshed the snapshot + regenerated (531 → 546 codes), and added __tests__/registry-sync.test.ts so an inventory refreshed without a regeneration (or vice versa) fails here rather than in production.

One existing expectation in parse.test.ts had to shrink: STEP_UP_REQUIRED_PASSWORD_OR_MFA is genuinely gone from constructive-db (616a2aefc14 split it into the per-factor STEP_UP_REQUIRED_PASSWORD / _MFA / _FRESH_AUTH codes, all still 403), so asserting it exists was asserting a stale snapshot.

Not addressed here: the cross-repo drift that caused this needs the audit re-run when constructive-db adds codes. This test only catches drift between the committed snapshot and the generated file, not between the snapshot and constructive-db — that needs a CI job with both checkouts, and belongs in the #1415 follow-up rather than in this package.

packages/errors tests: 39 passing.

Link to Devin session: https://app.devin.ai/sessions/087553534c774929918ec4d378845881
Requested by: @pyramation

…codes

httpStatusFor(code) is now the one place a transport asks for a status, and an
unregistered code is reported once instead of quietly answering 500. Refreshes
the constructive-db audit snapshot: 15 codes raised on main were missing from
the registry, so each of them was already surfacing as a 500.
@pyramation pyramation self-assigned this Aug 3, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit 32ce3d3 into main Aug 3, 2026
16 checks passed
@pyramation
pyramation deleted the feat/error-http-status branch August 3, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant