# Fix SvelteKit Exceptions From PostHog Error Tracking

Yes. An agent takes your top PostHog exception, traces it to the SvelteKit load or action that throws, adds a Vitest test, fixes it and opens a pull request.

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

## What the agent does

Through your PostHog connection the agent lists the project's error-tracking issues from the last 7 days and takes the one with the most occurrences. It reads the exception type, message, sample stack frames, the URL of each event and the first-seen time. In SvelteKit most data work happens in `+page.server.js` and `+layout.server.js`, so an exception users see is often thrown on the server during a `load` or a form action, and the URL (`/article/<slug>`, `/profile/@<user>/favorites`) names the route before the stack does.

Then it maps the frames to source in a clone of your repository in its own cloud sandbox. In sveltejs/realworld (SvelteKit 2.52, Svelte 5 with `runes: true`, the Vercel adapter) every request to the backend goes through `src/lib/api.js`. Its `send` returns the parsed body when the response is OK or when the status is 422, and calls `error(res.status)` otherwise. That second case is the one to watch: on a 422 the caller gets `{ errors }` back as if it had succeeded. `src/routes/article/[slug]/+page.server.js` destructures `{ article }` from `api.get('articles/<slug>')` and immediately runs `marked(article.body)`, so a 422 there becomes `Cannot read properties of undefined (reading 'body')`. The agent checks the PostHog message against paths like this one.

It reads the profile routes and the hook the same way. `src/routes/profile/@[user]/+layout.server.js` loads the profile, and `get_articles.js` builds the `limit` and `offset` query for both the author and favorites pages from `+url.searchParams.get('page') || 1`. `src/hooks.server.js` sets `locals.user` with `JSON.parse(atob(jwt))` from the `jwt` cookie, which throws on every route for a visitor whose cookie is malformed. The article page's `toggleFavorite` action calls `api.post` and `api.del` without `await`, so a failure there surfaces as an unhandled rejection rather than on the page. Each of these leaves a different signature in PostHog, which is how the agent tells them apart.

The project has no test runner and no CI workflow, so the agent adds Vitest as a dev dependency with pnpm (the repository pins `pnpm@10.20.0` and Node 20 in `.nvmrc`), writes a test that calls the `load` or action with the input from the PostHog events (a stubbed `fetch` returning the 422 body, a bad cookie, a `page` value) and expects the failure, fixes the code, and runs `npx vitest run` and `pnpm run lint`. It opens a pull request that names the PostHog issue and its occurrence count.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "Use the PostHog connection to list this project's error-tracking issues from the last 7 days and take the one with the most occurrences. Read its exception type, message, sample stack frames, URLs and first-seen time. Map the frames to the source in the article and profile routes (src/routes/article/[slug]/, src/routes/profile/@[user]/) and the code they share (src/lib/api.js, src/hooks.server.js). Add Vitest as a dev dependency with pnpm, reproduce the exception with a Vitest test that calls the load function or form action with the input from the events, fix it, and run npx vitest run and pnpm run lint until both pass. Open a pull request that names the PostHog issue, its occurrence count and first-seen time, and quotes one sample stack trace. If the cause is outside this repository, say so in the session result and open no pull request.",
  "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 named after the exception. In the RealWorld app it changes the route file that threw, or `src/lib/api.js` when the cause is the 422 handling every caller shares, and adds a test file beside it. Because the project had no tests, the pull request also adds `vitest` to `devDependencies`, a `test` script and the `pnpm-lock.yaml` change, and the description says so. It carries the PostHog issue, the occurrence count over 7 days, the first-seen time, one sample stack trace and the line it maps to.

There are no GitHub Actions workflows in this repository, so nothing runs on the pull request unless your fork adds one (or the Vercel integration builds a preview). The session transcript is the record: the PostHog queries, the failing test, the fix, and the passing `npx vitest run` and `pnpm run lint` with their output.

Before merging, a reviewer checks the shape of the fix. A change to `api.js` affects every route, so it should keep the 422 bodies the forms rely on for `ListErrors`, and a route-level fix should turn the bad response into a SvelteKit `error()` or a `fail()` rather than an empty page. The new test should fail on `main`. After the deploy, the PostHog issue should stop receiving events.

## Run it on every release that raises errors

Have your deploy job send the request a day after each production release, with your PostHog connection named in `connections`. The agent then works on whatever the release made most frequent, while the change that caused it is still fresh.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` with the `session_url` when the turn finishes, so the deploy job can post the pull request link where the release was announced. A key runs at most `max_concurrent` sessions at once (4 by default) and answers `429` past that.

## Why run it on Rush?

Server-side exceptions in SvelteKit need the server to reproduce: `pnpm install`, the Vite dev server or a test that calls `load` directly, and a stub for the backend the routes call. In a Rush sandbox the agent sets that up on its own machine, so it can add a test runner and stub `fetch` on a branch without touching anyone's local setup or the shared backend.

The proof is in the pull request and the transcript: the PostHog numbers it chose by, the stack trace, the test that fails before the fix, and the passing runs. For a repository with no CI that record is what a reviewer has, and it is all there. Different issues or different apps can each run in their own sandbox at once.

## Frequently asked questions

### Will the test call the real RealWorld API?

No. `src/lib/api.js` uses the global `fetch`, so the test stubs it and returns the status and body the PostHog events point to, such as a 422 with `errors`. Nothing leaves the sandbox.

### Why add Vitest instead of reproducing in the browser?

A test keeps the reproduction in the repository, so the bug cannot come back unnoticed. If you would rather not add a dev dependency, say so in the prompt and the agent reproduces it in the sandbox browser against `pnpm dev` and lists the steps in the pull request.

### What if the top exception comes from the backend being down?

Then `api.js` calls `error(res.status)` with a 5xx and SvelteKit renders `+error.svelte`, which is the intended behaviour. The agent reports that in the session result and opens no pull request, since the cause is outside the repository.

### Does the request need the PostHog connection named?

Yes. A key run gets only the connections it names, so add `"connections": ["posthog"]` (or the connection's id) to this request after you connect PostHog once with `POST /me/connections`.
