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

Yes. From a Sentry alert the agent reads the stack trace, reproduces the failing load or action with a Vitest test in your SvelteKit app and opens a pull request.

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

## What the agent does

A Sentry alert for a SvelteKit app names a server `load` function or a form action most of the time, and the agent starts there. Through the Sentry connection it reads the issue and its latest event: the exception, the request URL and method, the release, and the in-app frames with their file paths and line numbers. It compares the frames against the route tree in its clone of the repository, so a frame in `src/routes/article/[slug]/+page.server.js` is matched to the article page's `load` and its `createComment`, `deleteComment`, `deleteArticle` and `toggleFavorite` actions before any code is read.

In a SvelteKit app like sveltejs/realworld the agent reads `package.json` first: SvelteKit ^2.52.2 on Svelte ^5.55.7 with `runes: true` in `svelte.config.js`, Vite ^7.3.2, `adapter-vercel`, `marked` and `sanitize-html`, and `packageManager` set to pnpm 10.20.0 with `.nvmrc` at 20 and `engine-strict` in `.npmrc`. There is no test script and no test runner; the only check is `prettier --check .` as `pnpm lint`. Every request goes through `src/lib/api.js`, whose `send` fetches `https://api.realworld.show/api`, returns the parsed body on an ok or 422 response, returns `{}` on an empty body and otherwise calls SvelteKit's `error(res.status)`. The article loader runs `api.get` for the article and its comments in a `Promise.all`, then `marked(article.body)` and `sanitizeHtml`. The profile routes under `src/routes/profile/@[user]/` load `profiles/{user}` in `+layout.server.js` and the author's articles through `get_articles.js`, which builds `limit` and `offset` from `page_size` in `src/lib/constants.js`. `src/hooks.server.js` sets `locals.user` by `JSON.parse(atob(jwt))` on the cookie, which is itself a place a malformed cookie throws.

Because the project has no runner, the agent adds `vitest` as a dev dependency and a `test` script, keeping `@sveltejs/vite-plugin-svelte` that is already installed for Vite. It writes a test that imports the loader or action from the route file and calls it with a hand-built event: `params` from the event's URL, `locals` with or without a user, and a mocked `fetch` or a mocked `$lib/api.js` that returns the body the Sentry event implies, such as `{}` from an empty response or an article with no `body`. It runs `npx vitest run` and keeps the failing output, which shows the same exception type and message as the Sentry event.

Then it fixes the cause in the loader or action, reruns the test until it passes and runs `pnpm lint` and `pnpm build` so the Vercel adapter still builds. If the frame was in `+page.svelte` rather than a loader, it reads the component with `data` from `$props()` and fixes what the template assumes about the data, such as `data.article.author`, with a test for the loader that feeds it. It does not wrap the loader in a blanket `try` that hides the status; `+error.svelte` already renders a 404 and a generic page, and the fix keeps that behaviour.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for this SvelteKit app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request URL and the in-app stack frames. Match the frames to the route files under src/routes, starting with the article route in src/routes/article/[slug]/+page.server.js and the profile routes under src/routes/profile/@[user]/, and to the fetch wrapper in src/lib/api.js. The project has no test runner: add vitest as a dev dependency with a test script, write a test that calls the failing load function or form action with a mocked API response and reproduces the exception, then fix the cause until `npx vitest run` passes. Install with pnpm, and run `pnpm lint` and `pnpm build`. 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

The result is a pull request with a small diff: the route file where the exception started, a new test file beside it, `vitest` under `devDependencies` with a `test` script in `package.json`, and the updated `pnpm-lock.yaml`. The description links the Sentry issue, names the loader or action and the line, shows the test failing before and passing after, and explains in plain words why the code threw, for example that an empty API response reaches `marked` as `undefined`.

The session holds the full record: the Sentry queries, the `pnpm install`, `vitest`, `lint` and `build` commands with their output, and the files the agent read. Its final message, the `result` on the session and `data.result` in the `run.completed` webhook, is the short account a reviewer reads first; the transcript is where they check it.

Before merging, the reviewer confirms the test calls the same code path Sentry reported, that a fix which now throws `error(404)` or `error(502)` chooses the status the API answer deserves rather than hiding it, and that nothing in `src/lib/api.js` changed for routes that were working. A different approach is a follow-up message to the same session, and the agent amends the same branch.

## Run it on every new Sentry issue

Add an alert rule in Sentry for the SvelteKit project that fires when a new issue is created, with a webhook action aimed at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the issue id as the `Idempotency-Key`, so Sentry's retries map to one run. Every new issue gets its own sandbox, its own test and its own pull request.

Give the API key a webhook URL and Rush POSTs `run.completed` when the turn ends, with `session_url` to read the pull request from. 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?

A SvelteKit loader fails on an API answer that is hard to get a browser to produce again, so reproducing it on a laptop means stubbing `fetch` by hand and wiring a test runner into a project that never had one, all while something else is half-done on your branch. In a Rush sandbox the agent sets up Vitest on its own disk, mocks exactly the response the Sentry event shows and leaves your working tree alone.

What you get back can be checked instead of trusted: the test that failed, the test that passes and the transcript of every command the agent ran. Each Sentry issue runs on its own, in parallel up to the key's `max_concurrent` limit, so a release that opened several issues gets several reviewed fixes rather than one person triaging them in order.

## Frequently asked questions

### The project has no tests. Does the agent still write one?

Yes. It adds Vitest as a dev dependency and a `test` script, because the repository has only `prettier --check` as a check. The test targets the loader or action directly with a mocked API, so it runs in a few seconds without a browser. If you already use Playwright instead, say so in the prompt and it writes a spec there.

### The Sentry frames point into the Vercel build. Can it still find the line?

Server-side frames from `adapter-vercel` name the built files, so the agent maps them back through the route structure and the function names in the event, and says in the pull request which frames it placed and which it inferred. Uploading source maps to Sentry with a release makes the next event point at `src/routes` directly.

### Which package manager does it use?

pnpm, because `package.json` sets `packageManager` to pnpm 10.20.0 and `.npmrc` has `engine-strict=true`. The sandbox uses Node 20 from `.nvmrc` and commits the updated `pnpm-lock.yaml` with the new dev dependency.

### Will it change src/lib/api.js?

Only when the frames point there, for example an empty 200 response reaching `JSON.parse`. A change there affects every route, so the pull request calls it out and the test covers the exact response that broke, and the reviewer decides whether a narrower fix in the route is better.
