tRPC server returns HTTP 200 for every error, including UNAUTHORIZED #22
Labels
No labels
area/auth
area/backend
area/ci
area/deploy
area/e2e
area/frontend
area/shared
blocked
good-first-issue
needs-info
priority/high
priority/low
priority/medium
type/bug
type/chore
type/docs
type/feature
type/tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
celilo/lunacycle#22
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
responseMetainapps/lunacycle-server/src/index.tshard-codesstatus: 200on every tRPC response, so error envelopes are served with a success status.Reproduce against production:
Note the body itself carries
httpStatus: 401— tRPC computed the correct status andresponseMetadiscarded it.Impact. Any client that checks the HTTP status cannot distinguish success from auth failure or a server error. This is not hypothetical: it made the production
smoke_apihealth check unfalsifiable, reporting✓ API responded (HTTP 200)while the server loggedERR_JWS_INVALIDfor that exact request. Found in #20; the smoke checks now work around it by asserting on the response body instead (assertNoTrpcErrorinscripts/smoke/api-smoke.ts), but the underlying behavior is unchanged for every other consumer — monitoring, proxies, browser devtools, and any future client.Fix. Return the status tRPC already computed rather than a constant. The headers block in the same
responseMetais doing real work (CORS + security headers) and should stay.Watch out for. The SPA may have grown code that assumes 200-always — worth grepping before changing, and worth checking whether Caddy or any monitoring keys off the status.
Found while investigating the first-ever production run of the smoke checks (#20).