# Turn Sentry Errors Into Fix Pull Requests for a Nuxt App

Yes. A Sentry alert starts the run; the agent maps the frames to your Nuxt pages and composables, reproduces the error with Vitest and opens a pull request.

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

## What the agent does

The agent reads the alert payload after the prompt, then asks Sentry for the issue and its latest event through the connection: the error message, whether it was thrown on the server during rendering or in the browser after hydration, the page URL, and the in-app frames. In a Nuxt app those two cases point at different code, so it settles that first. A server-side frame names a page's top-level `await` or a composable; a browser frame names a component method or a `computed`.

In a Nuxt app like nuxt/movies it then reads the project in its clone. `package.json` runs `nuxt-nightly` at 4.6.0 with `compatibilityVersion: 5` in `nuxt.config.ts`, pnpm 11.1.2 and Node ^24 under `devEngines`, Vitest ^4.1.11 with `@nuxt/test-utils`, `@vue/test-utils` and `happy-dom`, and Playwright for `tests/e2e`. Data comes from `app/composables/tmdb.ts`: `fetchTMDB` calls `$fetch` against `https://movies-proxy.vercel.app/tmdb`, keeps one promise per request hash in an `LRUCache` and the answer in `useState`, and deletes the cache entry when the request rejects. `getMedia` throws `createError` with status 404 for ids in its `blocked` set; `listMedia`, `getRecommendations` and `searchShows` filter those ids out of `results`. `app/pages/[type]/[id].vue` awaits `getMedia` and `getRecommendations` in a `Promise.all` at the top of `<script setup>` and then passes `item.poster_path` to `$img` inside `useHead`; `app/pages/person/[id].vue` does the same with `getPerson`. `app/composables/item.ts` reads `item.videos?.results?.find` for the trailer, and `app/composables/utils.ts` formats dates, runtimes and vote counts. `app/error.vue` renders the thrown error for anything that is not a 404.

The test goes where the repository already keeps them. `vitest.config.ts` includes `**/composables/**/*.test.ts`, `**/components/**/*.test.ts` and `tests/unit`, and the existing files use the `.nuxt.test.ts` suffix so `@nuxt/test-utils` runs them in the Nuxt environment, with `mockMedia` and `mockPerson` from `tests/unit/mocks.ts` building fixtures. The agent writes a test next to the composable or component the frames name, feeds it the shape the Sentry event implies, such as a media item with no `poster_path` or a `videos` object with no `results`, and runs `pnpm vitest run <file>`. The failing output is kept as the reproduction.

Then it fixes the cause, in the composable, the page or the component, reruns the test until it passes, and runs the three commands the `tests-unit.yml` workflow runs: `pnpm run test:unit`, `pnpm run lint` with the antfu ESLint config, and `pnpm run typecheck` through `nuxt typecheck`. A fix that changes a page's `useHead` or a `v-if` is checked against the Playwright specs in `tests/e2e` when the browsers install in the sandbox. The agent does not add a `catch` that turns a failed TMDB request into an empty page; where the right behaviour is a 404, it throws `createError` as `getMedia` already does for blocked ids.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for this Nuxt app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, whether it happened on the server or in the browser, and the in-app stack frames. Match the frames to the pages under app/pages, the composables in app/composables (start with tmdb.ts and item.ts) and the components under app/components. Write a Vitest test with the .nuxt.test.ts suffix next to the failing composable or component, using the mocks in tests/unit/mocks.ts, that reproduces the error, then fix the cause until `pnpm run test:unit` passes. Install with pnpm, then run `pnpm run lint` and `pnpm run typecheck`. Open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Change nothing unrelated to this error.\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

You get a pull request whose diff is the fix in one page, composable or component plus one new `.nuxt.test.ts` file beside it. The description links the Sentry issue, says whether the error was server-rendered or client-side, quotes the frames it placed, shows the test failing before and passing after, and lists the `test:unit`, `lint` and `typecheck` commands with their summary lines.

The session's transcript keeps every Sentry call, every command and its output, and every file read, so the reviewer can see that the typecheck passed rather than read a sentence saying so. The `run.completed` webhook carries the agent's final message as `data.result` and a `session_url` for the rest.

Before merging, the reviewer checks that the test reproduces the reported error and not a neighbouring one, that a change in `tmdb.ts` still deletes the cached promise when a request rejects so a transient failure is not pinned for the cache's lifetime, and that the page still renders the 404 path for blocked ids. Follow-up messages to the same session change the branch in place.

## Run it on every Sentry issue alert

Create an alert rule in the Sentry project with a webhook action and point it at a handler on your server. The handler adds the alert's JSON after this prompt, sends the request with the issue id as `Idempotency-Key`, and returns. A resent alert returns the same run, so one issue never becomes two pull requests.

Set a webhook URL on the key and Rush POSTs `run.completed` with `session_url` when the pull request is ready; your handler can comment the link on the Sentry issue. Or have that handler call a `webhook` trigger on an automation in the Project with this prompt: it forwards the alert's JSON as the body with the trigger's secret as `Authorization: Bearer`, because Sentry signs its own webhooks and cannot send that header. The body becomes the event text after the prompt, and `max_runs_per_hour` caps an issue that keeps firing.

## Why run it on Rush?

Nuxt errors split into server-render and browser cases, and reproducing either by hand means guessing which API response the page saw. The agent reads that from the Sentry event, builds the fixture with the repository's own mocks and runs the project's unit, lint and typecheck commands in a sandbox with the right pnpm and Node, while your own checkout stays untouched.

The pull request brings the evidence: a test that failed, the same test passing, and a transcript of each command. Each issue is its own run, so a release that broke the detail page and the person page at once produces two separate branches, worked in parallel up to the key's `max_concurrent` limit, each small enough to review in a few minutes.

## Frequently asked questions

### Does it need the TMDB proxy to run the tests?

No. The unit tests mock the composable's input with `mockMedia` and `mockPerson` from `tests/unit/mocks.ts`, so they do not call `https://movies-proxy.vercel.app`. The Playwright specs in `tests/e2e` do reach the proxy, and the agent runs them only when the fix touches a page they cover.

### How does it tell a server error from a browser error?

The Sentry event says which SDK sent it and carries the request or the browser context. A frame in a page's `<script setup>` `await` or in a composable called during render is server-side under Nuxt's SSR; a frame in a click handler or a `watch` is client-side. The pull request states which it was, because the fix and the test differ.

### Will it change nuxt.config.ts?

Not for a code error. The config sets the proxy base URL, the i18n locales and the html-validator rules, and none of those cause an exception in a page. If the frames point at a module option, the agent says so in the pull request and keeps the change to that option.

### The frames point at a nightly Nuxt build. Can it still fix my code?

The agent fixes the code in `app/`, not the framework. When the top in-app frame is inside `nuxt-nightly` itself, it says so and proposes the smallest change on your side that avoids the path, or opens no pull request and reports what it found.
