fix: 400 instead of 500 null dev id - #863
Merged
Merged
Conversation
POST /api/billing/deduct already validated developerId correctly at the route boundary, but the validation error never reached the client as a 400. idempotencyMiddleware declares an optional 4th `opts` parameter, giving it an arity of 4 — Express treats any 4-arg middleware as an error handler, so registering it directly in the route chain caused thrown errors (including BadRequestError from a null/invalid developerId) to be misrouted into it instead of the real error handler, corrupting the request and surfacing as a 500. Wrap it in a 3-arg handler (same pattern already used in routes/exports/schedules.ts) so Express dispatches it as normal middleware. Also fixes a duplicate-import syntax break and a buildErrorEnvelope/ errorEnvelope typo in errorHandler.ts left over from a prior careless merge — both were causing every error response in the app to throw instead of returning JSON, which is what actually turned the null-dev-id 400 into a 500 (and was blocking most of the existing test suite). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@driftsorbit Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
Merged into main via admin resolver (-X theirs). |
Contributor
|
Solid PR — merging. Appreciate the effort! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #624 —
POST /api/billing/deductreturned 500 instead of 400 whendeveloperIdwasnull.Root cause:
deduct.tsregisteredidempotencyMiddlewaredirectly in the route chain. That function declares an optional 4thoptsparameter ((req, res, next, opts?)), giving it an arity of 4. Express treats any 4-arg middleware function as an error handler ((err, req, res, next)), regardless of intent. So whenever a downstream error was thrown — including the existingBadRequestError("developerId is required")validation — Express misrouted it intoidempotencyMiddlewarewith shifted arguments instead of the real error handler, corrupting the request and ultimately surfacing as a 500.The route-level input validation for
developerId(rejectnull/empty/non-string, default to the authenticated user when omitted) was already correct — this was purely an error-dispatch bug. Fixed by wrapping the middleware in a 3-arg handler before registering it, matching the pattern already used insrc/routes/exports/schedules.ts.While tracing the failure I also found two unrelated pre-existing breaks in
src/middleware/errorHandler.tsfrom an earlier careless auto-merge (-X theirsconflict resolution): a duplicate import block (hard syntax error) and a call to an undefinedbuildErrorEnvelope(should beerrorEnvelope). Both caused every error response in the app to throw instead of returning JSON, and were blocking most of the existing test suite (51 pre-existing failures undersrc/routes/billingbefore this PR, 7 after — the remaining 7 are unrelated stale-test issues, e.g. portal totals and bulk-route error-shape assertions, not touched here). Fixed both as they're required to actually observe the 400 response and unblock CI.Changes
src/routes/billing/deduct.ts: wrapidempotencyMiddlewarein a 3-arg handler so Express doesn't misidentify it as error middleware.src/middleware/errorHandler.ts: remove duplicate import block; fixbuildErrorEnvelope→errorEnvelopetypo.src/routes/billing/deduct.test.ts(new): covers null/empty/non-stringdeveloperId→ 400, omitteddeveloperId→ falls back to authenticated user, and unauthenticated → 401.docs/sdk/billing-deduct.md: document thedeveloperIdfield and its validation/error behavior.Test plan
npx jest src/routes/billing/deduct.test.ts— 5/5 passingnpx jest src/routes/billing— 106/113 passing (up from 62/113 onmain; remaining 7 failures are pre-existing and unrelated to this change)npx tsc --noEmit— no new type errorsnpx eslint src/routes/billing/deduct.ts src/routes/billing/deduct.test.ts src/middleware/errorHandler.ts— clean