Error reporting
Errors nobody expected, in the API, the web app and the mobile app, are reported to
Sentry with who was signed in and what they were doing. It is off until you
set SENTRY_DSN; until then errors are logged, as always, and go nowhere else.
Turn it on
Section titled “Turn it on”Create a Sentry project and copy its DSN from Settings > Client Keys:
SENTRY_DSN=https://abc123@o123.ingest.sentry.io/456That one setting turns it on everywhere: the web app and the mobile app read it from
GET /api/config when they start, so no image is rebuilt for it. Sentry suggests a project per
platform. To do that, make three, set the API’s as SENTRY_DSN, and the others as
SENTRY_WEB_DSN and SENTRY_MOBILE_DSN. On Railway, put them in .env.railway.
What is reported
Section titled “What is reported”| From | What |
|---|---|
| API | A request that ends in a 500; a job given up on after its last attempt; an error inside Better Auth |
| Web app | An error a page throws, one nothing catches, and one in a promise nobody waited for |
| Mobile app | An error a screen throws, and one nothing catches |
An answer the API gives on purpose is not an error: a 400, a 402, a 404, or a 503 that says
something is not set up. Nor is a failed call to the API from the web or mobile app: the API
reports its own failures.
Each report says who was signed in (their id), the workspace, and for a request its method,
route, path and x-request-id, the id on its log line.
A job’s report says its type and how many times it ran.
Errors in the web app from before Sentry has loaded, such as the app failing as it starts, are kept and sent once it has. In the mobile app, an error before the API has answered is not reported.
What is left out
Section titled “What is left out”Never a password, a token or a cookie. Whatever Sentry would collect, the API, the web app and the mobile app send:
- a request’s method and path, never its headers, cookies, query string or body;
- a person’s id, never their email, name or IP address;
- the addresses of requests and pages in breadcrumbs, without their query strings.
The rules are in packages/contracts/src/error-reports.ts, shared by the three, with a test.
Errors only: Sentry records no performance traces, which are
OpenTelemetry’s job, and no session replays.
The real line, in the version that threw it
Section titled “The real line, in the version that threw it”Each report is filed under a release: the commit on Railway (RAILWAY_GIT_COMMIT_SHA), or
SENTRY_RELEASE elsewhere. The mobile app’s release is its version and build number.
The API runs its TypeScript as it is, so its errors point at the right line with nothing to upload.
The web app is minified. With SENTRY_AUTH_TOKEN set when it is built, the build sends its
source maps to Sentry and leaves them out of what is served. Make the token under
Settings > Auth Tokens with the project:releases scope, and set:
SENTRY_AUTH_TOKEN=sntrys_…SENTRY_ORG=acmeSENTRY_WEB_PROJECT=webOn Railway, .env.railway passes them to the web app’s build only; the API never sees the token.
A build whose upload fails still finishes, and says why in its log.
The mobile app sends its source maps from EAS builds. Add SENTRY_AUTH_TOKEN, SENTRY_ORG and
SENTRY_PROJECT (the mobile app’s project) as
EAS environment variables, the token as a
secret. Without them the build finishes without sending any: eas.json sets
SENTRY_ALLOW_FAILURE. Sentry needs native code, so make a new development build once
(Mobile builds); Expo Go has it already.
Report one yourself
Section titled “Report one yourself”Most errors need nothing: throw, and the API reports what would be a 500. For an error you catch and recover from, but want to know about:
constructor(@Inject(ERROR_REPORTER) private readonly errors: ErrorReporter) {}
this.errors.capture(error, { workspaceId: workspace.id });In the web app, errors.capture(error) from src/lib/errors.ts; in the mobile app, the same from
its src/lib/errors.ts.
Another service
Section titled “Another service”Sentry is behind ErrorReporter in apps/api/src/errors/error-reporter.ts, and in one file in
each app: apps/web/src/lib/sentry.ts and apps/mobile/src/lib/errors.ts. Replace those, and the
variables in config/env.ts and GET /api/config.
Test it
Section titled “Test it”createTestApp({ teams, errors: new FakeErrorReporter() }) keeps every error the API would
report, with its context. See apps/api/test/errors.e2e.test.ts.