Repository navigation
Keep a tRPC fault's text off the browser - #141
Merged
Merged
Conversation
A procedure that threw an unexpected error, a failed database query for one, answered the dashboard with that error's own message: tRPC copies an unknown error's message into the INTERNAL_SERVER_ERROR it builds, so the SQL, table and column names and query parameters reached any signed-in user. Outside production the response carried its stack too. The router's error formatter now answers every INTERNAL_SERVER_ERROR with a general message, and only `next dev` keeps the original message and stack. Refusals with any other code keep their message, validation details included. The route's onError now also logs the error, which until now reached only error tracking, and so nowhere without SENTRY_DSN. The invitation resend's send failure was the one deliberate 500 with copy of its own, localized for its dialog; it answers SERVICE_UNAVAILABLE now, so the dialog still says the email could not be sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
The leak
When a dashboard procedure threw an unexpected error, for example a failed database query, the 500 sent to the browser carried that error's own text. tRPC copies an unknown error's message into the
INTERNAL_SERVER_ERRORit builds. So a drizzleFailed query: select … params: …reached any signed-in user, with SQL, table and column names and query parameters. Outside production the response also carried the stack, which repeats the message. Nothing in the app set anerrorFormatter, so tRPC's default shape went out as is.The fix
apps/web/src/server/trpc.ts: the router'serrorFormatterswaps the message of everyINTERNAL_SERVER_ERRORfor a fixed one: "Something went wrong. Try again, or contact support if it keeps happening." Onlynext dev(NODE_ENV=development) keeps the original message and stack. The same flag goes to tRPC'sisDev, because its default (any NODE_ENV except production) would send the stack in tests.apps/web/src/app/api/trpc/[trpc]/route.ts:onErrornow alsoconsole.errors the fault, as the REST API'sonErrordoes. Until now it only reached error tracking, so an instance withoutSENTRY_DSNrecorded it nowhere. Reporting is unchanged:captureErrorstill gets the original error with its procedure and team.settings.invitations.resend: this was the one deliberate 500 with copy of its own, the localized "the invitation email could not be sent" its dialog shows. It now answersSERVICE_UNAVAILABLE, so the dialog keeps that message. Side effect: this refusal is no longer sent to error tracking (onError reports 500s only). The send error itself is still logged where it happens, the same as the invite-create path, which never reported it.Public REST API and MCP
Both were already generic, so neither changes here:
apps/apiapp.onErroranswers any unhandled error with500 internal_server_error"An unexpected error occurred", after logging and reporting it.apps/api/test/error-tracking.test.tsalready pins that body.app.fetch), so a fault reaches the agent as that same generic body. If token verification fails with something other than an OAuth error, the SDK answers500 server_error"Internal Server Error".Tests
apps/web/test/error-tracking.test.tsdrives the real/api/trpcroute and router:Failed query: select "secret" …error gets a 500 whose body is the generic message, with no SQL text and no stack. This fails without the fix.pnpm lint,pnpm typecheckand the web suite (1218 tests) pass.🤖 Generated with Claude Code