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

Yes. An agent reads the Sentry issue, reproduces the failing Hono route in a Workers Vitest test, fixes the handler and opens a pull request that links the issue.

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

## What the agent does

The agent reads the alert payload after the prompt, then fetches the issue and its latest event through the Sentry connection: the exception type and message, the request method and URL, the tags for release and environment, and the in-app stack frames. For a Worker the frames point at the bundled script, so the agent keeps the message and route and matches them to source rather than to a line number.

In a repository like honojs/examples the blog example is a Cloudflare Worker in `blog/`, with `hono` pinned to `^4.2.4` and `wrangler`, `vitest` 1.3.0 and `@cloudflare/vitest-pool-workers` as dev dependencies; `blog/vitest.config.ts` uses `defineWorkersConfig` with `isolatedStorage: false` and the `wrangler.toml` that `wrangler.example.toml` becomes, which binds the KV namespace `BLOG_EXAMPLE`. `blog/src/index.ts` mounts a basic-auth middleware on every non-GET under `/api/posts/*` using `USERNAME` and `PASSWORD` from the bindings, then mounts the API; `blog/src/api.ts` defines `GET /posts`, `POST /posts`, `GET /posts/:id`, `PUT /posts/:id` and `DELETE /posts/:id`; and `blog/src/model.ts` stores each post under a `v1:post:` key as JSON.

A Sentry issue on this app almost always lands in one of a few places the agent reads first. `POST /posts` and `PUT /posts/:id` call `await c.req.json()` with no guard, so a request with a malformed body or the wrong content type throws before `model.createPost` can answer 422. `getPosts` in `model.ts` calls `JSON.parse` on every value it lists, so one hand-edited KV value breaks the whole list. `PUT` and `DELETE` return a bare `204` for a missing post where every other route returns JSON, which a client that always parses the body turns into an exception of its own.

The agent writes the reproduction in `blog/src/api.test.ts`, which already drives the app with `worker.request('/posts', …, env)` and the `env` from `cloudflare:test`, adds a case that sends the failing request and asserts the status the route should return, and watches it fail with the Sentry message. It then fixes the handler, for example by catching the parse error and answering 400 with `{ error, ok: false }`, runs `npm test` in `blog/`, which is `vitest --run`, and `npx tsc --noEmit` against `blog/tsconfig.json`, and opens a pull request that links the Sentry issue and quotes the frames.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for the blog Worker in this repository; the payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request method and URL, the tags and the in-app frames. Find the handler in blog/src/api.ts, blog/src/index.ts or blog/src/model.ts that the message and route point at. Add a test to blog/src/api.test.ts that sends the same request through worker.request with the env from cloudflare:test and asserts the response the route should give; confirm it fails with the same error. Fix the cause rather than wrapping the route in a try/catch that hides it, keep the JSON response shape the other routes use, run npm test in blog and npx tsc --noEmit, and open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Change nothing outside the blog example.\n\nAlert payload:\n{payload}",
  "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 touching `blog/src/api.ts` or `blog/src/model.ts` and `blog/src/api.test.ts`, usually under thirty changed lines. Its description links the Sentry issue, quotes the exception message and the route from the event, shows the new test failing before the change and passing after, and gives the `npm test` summary from the Workers pool and the `tsc` result.

The reviewer checks that the fix returns a status and a body consistent with the rest of `api.ts`, that a bad request is now 400 or 422 and not a silent 200, that the basic-auth middleware in `index.ts` still applies to the method in question, and that no KV key format changed. If the cause was data, a corrupt value under `v1:post:`, the description says so and the fix makes `getPosts` skip or report that value rather than fail the list.

## Run it on every Sentry issue alert

Create an alert rule in the Sentry project for the Worker with a webhook action pointed at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the Sentry issue id as `Idempotency-Key`, so a retried delivery returns the run already started. Sentry cannot call a Rush `webhook` trigger directly, because the trigger needs `Authorization: Bearer` with its secret; the handler adds that header if you prefer an automation in the Project over a direct session.

Give the API key a webhook URL and Rush POSTs `run.completed` with the `session_url` and the result when the turn ends; the handler can post the pull request link back on the Sentry issue as a comment. An issue that keeps firing should not keep opening pull requests, so the handler dedups on issue id, or the automation's `max_runs_per_hour` does.

## Why run it on Rush?

A Worker bug is cheap to fix and tedious to reproduce: the test pool needs `wrangler` and a KV binding, and the developer who gets the alert is usually working on something else. The agent does the setup in its own sandbox, runs the one test that matters, and hands back a diff. Several alerts from several example apps in the same repository can be several sessions.

The pull request carries its own evidence. The transcript shows the Sentry event the agent read, the test failing with the same message and passing after the change, and the exact `npm test` output, so the reviewer judges the fix rather than reconstructing the bug.

## Frequently asked questions

### Does the Workers test pool run in the sandbox?

Yes. `npm install` in `blog/` brings `wrangler` and `@cloudflare/vitest-pool-workers`, and `vitest.config.ts` points at `wrangler.toml` for the `BLOG_EXAMPLE` KV binding. The pool provides a local KV, so the test needs no Cloudflare account.

### Stack frames from a Worker point at the bundle. How does the agent find the source line?

From the message and the route. The event names the method and URL, and `blog/src/api.ts` has one handler per route, so the search is small. If source maps are uploaded to Sentry the frames resolve to `src/` lines directly and the agent uses them.

### Will it add a global error handler instead of fixing the route?

No. The prompt asks for the cause and forbids a try/catch that hides it. A route that throws on a malformed body should answer 400 with the same `{ error, ok }` shape the other routes use; an `app.onError` that turns every failure into a 500 JSON would silence Sentry without fixing anything.

### Does it work for the other examples in the repository?

The same prompt works for any example with a Vitest setup; the agent reads that example's `package.json` and config first. The Bun and Deno examples run their tests differently, so name the example and its test command in the prompt.

### What if the Sentry issue is from a release that no longer matches main?

The agent compares the release tag on the event with the current source. If the handler already changed, the pull request says the issue is likely fixed, still adds the test to prove the current behavior, and asks the reviewer to resolve the issue in Sentry rather than inventing a second fix.
