# Fix React Exceptions From PostHog Error Tracking

Yes. An agent takes your most frequent PostHog exception, maps it to the React feature that throws, reproduces it in Vitest, fixes it and opens a pull request.

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

## What the agent does

The agent asks PostHog first. Through your PostHog connection it lists the project's error-tracking issues from the last 7 days and takes the one with the most occurrences, then reads its exception type and message, sample stack frames, the URL of each event and the first-seen time. If every event comes from `/app/discussions/<id>` and started after one release, that already narrows the search to one route and one diff.

Then it maps the frames to source in a clone of your repository in its own cloud sandbox. In alan2207/bulletproof-react the Vite app lives in `apps/react-vite` (React 18.3, TanStack React Query 5, Vite 5) and is organised by feature. The discussions feature has `src/features/discussions/api/` with one file per request (`get-discussion.ts`, `get-discussions.ts`, `create-discussion.ts`, `update-discussion.ts`, `delete-discussion.ts`), each pairing a fetch through `@/lib/api-client` with a `useQuery` or mutation hook, and `components/` with `discussion-view.tsx`, `discussions-list.tsx` and the create, update and delete forms. Comments under a discussion come from `src/features/comments/`. The routes that compose them are in `src/app/routes/app/discussions/`.

Reading the code the frames point at, the agent looks for the assumptions that real data breaks. `DiscussionView` returns early while `isLoading` and when `data.data` is missing, and guards `discussion.author` before reading `firstName`. But `formatDate` in `src/utils/format.ts` takes a number and passes it to `dayjs`, and the list reads `discussionsQuery.data?.meta` for pagination from a `page` parsed with `+(searchParams.get('page') || 1)`, so a malformed `createdAt` or a `?page=abc` URL produces output the components do not expect. The PostHog event's URL and message tell the agent which of these, or which other path, is the one users hit.

It reproduces the exception with the tooling the app already has. Tests use Vitest with Testing Library, and `src/testing/` provides `renderApp`, `createUser` and `createDiscussion`, with MSW handlers in `src/testing/mocks/handlers/discussions.ts` and `comments.ts` backed by a mock database. The existing `src/app/routes/app/discussions/__tests__/discussion.test.tsx` renders the route at `/app/discussions/:discussionId`; the agent adds a case beside it that serves the data or URL from the PostHog events and expects the crash, fixes the component or hook, and runs `npx vitest run`, `yarn lint` and `yarn check-types` until they pass. The pull request 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. Work in apps/react-vite. Map the frames to the source in the discussions feature (src/features/discussions/api and components, src/features/comments, src/app/routes/app/discussions). Reproduce it with a Vitest test next to src/app/routes/app/discussions/__tests__/discussion.test.tsx, using renderApp and the MSW handlers in src/testing/mocks, fix it, and run npx vitest run, yarn lint and yarn check-types until all 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 bulletproof-react it usually changes one file under `src/features/discussions/` or `src/features/comments/` (a component that assumed a field, a hook whose query key or params let bad input through, a util like `formatDate` that got a value of the wrong type), adds a test to `src/app/routes/app/discussions/__tests__/`, and adjusts an MSW handler only if the test needs a new response shape. The description carries the PostHog issue, its occurrence count, the first-seen time, a sample stack trace and the line it maps to.

On GitHub the pull request runs `react-vite-ci.yml` in `apps/react-vite`: `yarn build`, `yarn test`, `yarn lint` and `yarn check-types`, plus the Playwright end-to-end job. The session transcript keeps the agent's own runs of the same commands with their output, and its queries to PostHog.

Before merging, a reviewer checks that the change handles the bad data where it enters (the API hook or the route that parses the URL) rather than adding an optional chain at the point of the crash, that the new test fails on `main`, and that the MSW handler still mirrors the real API. After the deploy, the PostHog issue should stop receiving events.

## Run it on every new top exception in PostHog

Run it from a daily scheduled job: the job asks the same question PostHog answers (which issue has the most occurrences) and sends the request only when the top issue is new since its last run, with your PostHog connection named in `connections`. That way a fix that has shipped is not attempted twice, and a new crash after a release gets a pull request the next morning.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` with the `session_url` when the turn finishes. A key runs at most `max_concurrent` sessions at once (4 by default) and answers `429` past that.

## Why run it on Rush?

Fixing a front-end exception properly means reproducing it, and in a React app that means installing with Yarn, running Vitest with jsdom and MSW, and checking types and lint, alongside the PostHog data that says what users hit. In a Rush sandbox the agent does all of that on its own machine, so a developer's working copy and running dev server stay untouched.

The result shows its work: the PostHog numbers it chose by, the stack trace and the source line, the test that fails before the fix, and every command with its output in the transcript. Different exceptions, or different apps in a monorepo like this one, can each run in their own sandbox at the same time.

## Frequently asked questions

### Will the test hit my real API?

No. bulletproof-react's tests run against MSW handlers in `src/testing/mocks/` with a mock database, and the agent's test does the same. It adds or changes a handler only when it needs to serve the shape the PostHog events show.

### The repository has three apps. Which one does it change?

The one the stack frames map to. The prompt names `apps/react-vite`; for the Next.js apps under `apps/nextjs-app` or `apps/nextjs-pages`, name that directory instead and the agent uses its own scripts and CI workflow.

### What if PostHog's frames are minified?

With source maps uploaded to PostHog the frames name files and lines. Without them, the agent builds the app with `yarn build`, matches function names and the message to the source, and says in the pull request how sure the mapping is.

### Does it need the PostHog connection named on the run?

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