All jobs

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 RushIn 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 Errors 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 with this body:

{
  "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.

The use case this job follows, with its automation and trigger: Fix a bug from an alert.

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.