# Fix Sentry Errors in a Next.js App

Send the Sentry issue to an agent: it reads the stack trace, reproduces the error in your Next.js app with a failing test, fixes the cause and opens a pull request.

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

## What the agent does

The agent reads the Sentry issue after the prompt and fetches its latest event through the Sentry connection: the exception type and message, the transaction name, the breadcrumbs that led to it, the release and environment tags, and the in-app frames. In a Next.js app the transaction tells it which side the error is on: a server action, a route handler under `app/api`, the middleware, or a client component.

In an app like nextjs/saas-starter, which pins `next` to 15.6.0-canary.59 with React 19.1, Drizzle, `postgres`, `stripe` and `jose`, the frames resolve to a handful of files. A transaction for `GET /api/stripe/checkout` points at `app/api/stripe/checkout/route.ts`, which throws plain `Error`s when the Stripe session has no customer, no subscription, no plan, no product id or no `client_reference_id`, and each of those messages is a Sentry title waiting to happen. `POST /api/stripe/webhook` points at `app/api/stripe/webhook/route.ts` and `handleSubscriptionChange` in `lib/payments/stripe.ts`, which casts `plan.product` to a `Stripe.Product` to read its name. A server action error names `signIn`, `signUp`, `inviteTeamMember` or `removeTeamMember` in `app/(login)/actions.ts`, where `validatedActionWithUser` throws `User is not authenticated` and `withTeam` throws `Team not found`. An error in `middleware.ts` comes from `verifyToken` on a stale session cookie.

Breadcrumbs matter here because the fix differs by path. A checkout error after a Stripe redirect is usually a session retrieved without the `expand` the code assumes; a webhook error is usually an event whose `items.data[0].plan.product` is a string id, not an expanded object; an action error is usually a form reaching the action after the session expired. The agent reads the breadcrumbs for the HTTP calls and navigation before the exception and writes down which of these it is seeing.

The repository has no test runner, so the agent adds Vitest with a minimal `vitest.config.ts`, writes one test that calls the route handler or action with the input the breadcrumbs describe, stubbing `stripe`, `getUser` or `db`, and confirms it fails with the Sentry message. It fixes the cause, handling the unexpanded product by retrieving it, or returning a redirect to `/pricing` with a message instead of throwing, runs `npx vitest run` and `pnpm build`, and opens a pull request that links the Sentry issue, quotes the frames and shows the test before and after. If it cannot reproduce the error it stops at `needs_review` and says what it tried.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry issue for this Next.js repository is attached below. Read its latest event through the Sentry connection: the exception, the transaction, the breadcrumbs, the release and environment tags and the in-app frames. Find the route handler, server action or middleware the frames name, starting with app/api/stripe/checkout/route.ts, app/api/stripe/webhook/route.ts, lib/payments/stripe.ts, app/(login)/actions.ts and middleware.ts. This repository has no test runner: add vitest with a minimal vitest.config.ts and write one test that calls the handler or action with the input the breadcrumbs describe, stubbing stripe, getUser and db, and confirm it fails with the same message. Fix the cause rather than catching the exception, run npx vitest run and pnpm build, and open a pull request that links the Sentry issue, quotes the frames and the failing test output and explains the cause. Stop at needs_review if you cannot reproduce it.\n\nSentry issue:\n{issue}",
  "connections": [
    "sentry"
  ],
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

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

What comes back is a pull request that changes one route handler, one function in `lib/payments/stripe.ts` or one server action, adds a test beside it, and adds `vitest` with its config when the repository had none. The description links the Sentry issue, quotes the exception title and the frames, states the cause in a sentence, shows the test failing and then passing, and lists `npx vitest run` and `pnpm build` with their results.

The reviewer checks that the stub returns what Stripe or Drizzle would return for the case in the breadcrumbs, that the fix handles the input rather than swallowing the error, and that user-facing behavior is still sensible: a checkout that cannot be completed should land on `/pricing` with a reason, not a blank 500. When the run ended `needs_review`, the session's result says what the agent could not reproduce and why, and there is no pull request to review.

## Run it on every Sentry issue alert

In the Sentry project create an alert rule for new issues with a webhook action to a handler on your server. The handler sends this request with the issue JSON after the prompt and the Sentry issue id as `Idempotency-Key`, so Sentry's retries return the run already started rather than opening a second pull request. A Rush `webhook` trigger needs `Authorization: Bearer` with its secret, which Sentry cannot send, so the handler is the piece that forwards.

With a webhook URL on the API key, Rush POSTs `run.completed` with the `session_url` when the turn finishes, and the handler can comment the pull request link on the Sentry issue. Regressions of resolved issues can use the same rule; the agent reads the release tag and says whether the current code still contains the frame.

## Why run it on Rush?

A Sentry issue from a Stripe redirect is hard to reproduce on a laptop: it needs a checkout session in the state the breadcrumbs describe, which means a test key, a webhook forwarder and a browser. The agent reproduces it from the event instead, in its own sandbox, and the developer reads a pull request with a failing test rather than a stack trace in a Slack channel.

Every claim in the pull request is backed by the transcript: the event the agent read, the test output before and after, the build output. A run that cannot reproduce the error says so and stops, which is worth more than a plausible patch that quiets the alert.

## Frequently asked questions

### Why add Vitest to fix one bug?

Because the repository has no test runner, and a pull request that claims to fix a Sentry error should show the error happening first. The addition is one dev dependency, one config file and one test. If you already use another runner, name it in the prompt and the agent uses that.

### Does the agent call Stripe?

Not from the test. `stripe` in `lib/payments/stripe.ts` is stubbed to return the object the breadcrumbs imply, for example a subscription whose `plan.product` is a string id. The fix may call Stripe in production code, such as retrieving the product when it was not expanded, and the pull request says so.

### What about errors on the client?

The transaction and frames say whether the error happened in a client component. For those the agent reproduces with a component test under Vitest and a DOM environment, and the fix lands in the component. Server-side errors, which are most of what this app can raise, are reproduced by calling the handler or action directly.

### Will it change the session cookie or auth logic?

Only when the frames land there, for example `verifyToken` in `middleware.ts` on a malformed cookie. Even then the change is limited to handling that case; the prompt forbids unrelated changes and the reviewer should hold it to that.

### Can one run fix several Sentry issues?

One issue per run is the design, so each pull request has one cause and one test. Send one request per issue; the handler's `Idempotency-Key` keeps repeated alerts for the same issue from starting a second run.
