# Fix Sentry Errors in an Express App

Yes. A Sentry alert starts a run; the agent reads the stack trace, reproduces the error with a Jest test against the Express service and opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/fix-sentry-errors/express/), in a Project that has your repository.

## What the agent does

The agent begins with the alert payload after the prompt and the Sentry connection: it fetches the issue and its latest event, reads the exception type and message, the request method, URL and query string, and the in-app frames with file, function and line. For a TypeScript Express service the frames point at the compiled output, so it keeps the function name and the route and matches them to the source by hand rather than trusting a line number.

In a service like gothinkster/node-express-realworld-example-app that source is small and regular. `src/main.ts` builds the app with `cors`, `body-parser` and the router from `src/app/routes/routes.ts`, which mounts the tag, article, profile and auth controllers under `/api`. Each controller in `src/app/routes/<name>/<name>.controller.ts` wraps its handler in `try`/`catch` and calls `next(error)`, and the error middleware at the bottom of `main.ts` answers 401 for `UnauthorizedError`, the `errorCode` of an `HttpException` from `src/app/models/http-exception.model.ts`, or 500 with the bare message for anything else. A Sentry event with a 500 therefore means an error that was neither an `HttpException` nor a JWT failure: a Prisma error from `src/prisma/prisma-client.ts`, a `TypeError` on a missing body, or a bad number from `Number(req.query.offset)` reaching `skip` in `getArticles`.

The agent reads the service the frames name, such as `getFeed`, `favoriteArticle` or `addComment` in `src/app/routes/article/article.service.ts`, and writes the reproduction where the repository already tests services: `src/tests/services/article.service.test.ts`, which imports `prismaMock` from `src/tests/prisma-mock.ts`, a `jest-mock-extended` deep mock of the Prisma client reset before each test. The new test arranges the mock to return what the Sentry breadcrumbs show the database returned, calls the service with the request's arguments, and asserts the `HttpException` the route should have thrown instead. It runs that file with `npx nx test api --testFile=article.service.test.ts` and keeps the failure.

Then it fixes the service so the case becomes a 404 or 422 `HttpException` with the `errors` body the RealWorld spec uses, or guards the input before it reaches Prisma, and reruns until the test passes. It runs the whole suite with `npx nx test api` (Jest 29 through `jest.config.ts` and `ts-jest`), `npx nx lint api`, and a TypeScript build with `npx nx build api`, which `project.json` defines with esbuild. There is no workflow in `.github/`, so those three commands are the checks the pull request reports.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for this Express service; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request method, URL and query, and the in-app frames. Match the frames to the controller in src/app/routes and the service function it calls. Add a test to the matching file in src/tests/services that uses prismaMock from src/tests/prisma-mock.ts to reproduce the database state the breadcrumbs show, calls the service with the same arguments, and asserts the HttpException the route should throw; confirm it fails with the Sentry error first. Fix the service so the case answers a proper status instead of a 500, keep the errors body shape the other routes use, then run npx nx test api, npx nx lint api and npx nx build api. Open a pull request that links the Sentry issue, quotes the exception and frames, and shows the test failing before the fix. Change nothing unrelated to this error. If you cannot reproduce it, open no pull request and say what you tried.\n\nAlert payload:\n{payload}",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ],
  "connections": [
    "sentry"
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

The result is a pull request on its own branch that changes one service file under `src/app/routes/` and adds one test to `src/tests/services/`. The description links the Sentry issue, quotes the exception and the frames it maps to, pastes the failing test output and the passing rerun, and lists the `nx test`, `nx lint` and `nx build` commands with their results. If the cause was a missing guard in the controller rather than the service, the diff is in the controller and the description says why.

The session holds the full record: each Sentry call, every command with its output, and every file the agent opened. `GET /o/{org}/sessions/{id}/messages` returns it, and the `run.completed` webhook on the API key carries the final summary in `data.result`, so the handler that received the Sentry alert can post the pull request link back on the issue.

A reviewer checks that the test's mocked Prisma result matches what the breadcrumbs actually showed, that the new status code is the one the RealWorld API spec expects for that case, and that the error middleware in `main.ts` was not widened to hide other 500s. A wrong fix gets a follow-up message to the same session and a new commit on the same branch.

## Run it on every Sentry issue alert

Give the Sentry project an alert rule with a webhook action pointed at a handler on your server. The handler sends this request with the alert JSON after the prompt and the Sentry issue id as the `Idempotency-Key`, so a redelivered alert returns the existing run. Each distinct issue becomes one run and one pull request.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` to it with the `session_url`. If you would rather keep the prompt in Rush, create an automation in the Project with a `webhook` trigger and have the handler forward the alert body to it with the trigger's secret as `Authorization: Bearer`; Sentry signs its own deliveries and cannot send that header. `max_runs_per_hour` on the automation stops a flapping issue from starting a run per event.

## Why run it on Rush?

An Express 500 from production is usually a small fix hidden behind an afternoon of setup: a Postgres `DATABASE_URL`, `prisma generate`, the Nx cache, and then guessing which request produced the trace. The agent reads the event through your connection, reproduces it against the mocked Prisma client the repository already tests with, and does it in a sandbox that leaves your checkout alone.

What you review is a pull request with a failing-then-passing test and a transcript of every command, not a description of a fix. Issues that arrive together after a deploy each run in their own sandbox, up to the key's `max_concurrent` limit, and nothing merges until a person approves it.

## Frequently asked questions

### The frames point at dist/api/main.js, not the TypeScript. How does it find the line?

It uses the function name and the route from the event, then reads the controller and service in `src/app/routes/` to find the matching code. `project.json` builds with esbuild and `sourcemap: true` in development, so when a source map is attached to the event it uses that directly.

### Does the test need a real Postgres database?

No. The repository's service tests mock the Prisma client with `jest-mock-extended` in `src/tests/prisma-mock.ts`, and the new test follows that pattern. If the bug is in a Prisma query itself, the agent says so and starts Postgres in the sandbox to run the query against `src/prisma/schema.prisma`.

### How does it get the Sentry issue?

Connect Sentry once with `POST /me/connections` and name it in `connections` on the run, as this page's request does. The run gets only the connections it names, and every call it makes appears in the transcript.

### What if the right fix is to change the error middleware?

It can, but the prompt asks for a status from the route first and the pull request has to explain any change to `src/main.ts`. A reviewer sees that change in the diff and can push back in a follow-up message on the same session.
