# Turn Sentry Errors Into Fix Pull Requests for an Angular App

Yes. A Sentry alert starts a run that follows the frames into your Angular services, reproduces the error in a Vitest spec and opens a pull request with the fix.

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

## What the agent does

An Angular Sentry event names the service method or component that threw, the route the user was on, the release and the breadcrumbs of `HttpClient` calls that came before it. The agent reads the alert payload after the prompt, fetches the issue and its latest event through the Sentry connection, and keeps the in-app frames, the breadcrumbs and the tags. Only then does it open its clone and read the files the frames point at.

In an Angular app like realworld-apps/angular-realworld-example-app (Angular 21.2.12, standalone components and signals), every request passes three functional interceptors in `src/app/core/interceptors`: `apiInterceptor` prefixes `https://api.realworld.show/api`, `tokenInterceptor` adds `Authorization: Token <jwt>` from `JwtService`, and `errorInterceptor` purges the session on any 401 except on `/user` and rethrows `{ ...body, status }`, substituting a single `network` message when the body carries no `errors`. `ArticlesService` in `src/app/features/article/services/articles.service.ts` maps `data.article` out of every response and `CommentsService` maps `data.comments`. `UserService` in `src/app/core/auth/services/user.service.ts` keeps an `authState` of loading, authenticated, unauthenticated or unavailable: a 4xx on `GET /user` logs the user out, while a 5xx or status 0 keeps the token and retries after 2, 4, 8 and then 16 seconds. `ArticleComponent` in `src/app/features/article/pages/article/article.component.ts` loads the article, its comments and the current user with `combineLatest` in `ngOnInit`, computes `canModify` from `article.author.username`, and a `catchError` writes `err.errors` into an `errors` signal. A frame in any of these tells the agent which response shape or which status the code did not expect.

The unit runner is Vitest, not Karma: `package.json` has `test` as `vitest`, and `vitest.config.ts` loads `@analogjs/vite-plugin-angular`, runs in jsdom, matches `src/**/*.spec.ts` and initializes `TestBed` once in `src/test-setup.ts` with `destroyAfterEach`. The existing specs beside each service (`articles.service.spec.ts`, `comments.service.spec.ts`, `user.service.spec.ts`, `jwt.service.spec.ts`, `tags.service.spec.ts`, `profile.service.spec.ts`) use `HttpClientTestingModule` and `HttpTestingController` to flush a canned response. The agent adds a case in the same style that flushes exactly what the breadcrumbs show, such as a 404 with an empty body, an article whose `author` is missing or a 204 with no body on `unfavorite`, and runs `bunx vitest run src/app/features/article/services/articles.service.spec.ts` so the failure is recorded before any fix.

With the failure reproduced it fixes the service, the component or, when the frames point there, the interceptor, reruns the spec until it passes, then runs `bun run format:check`, which is what the `lint.yml` workflow runs, and `bun run build`. The Playwright suite in `playwright.yml` needs the `realworld` submodule from `bun run setup` and `bunx playwright install --with-deps chromium`; the agent runs `bun run test:e2e` when that install succeeds and says so either way. It installs with Bun because `bun.lock` is the committed lockfile, on a Node that satisfies the `>=20.11.1` engines field. It does not widen `catchError` in `ngOnInit` to swallow the error: where the page should show a message instead of an empty article, it sets the `errors` signal and explains why.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for this Angular app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the breadcrumbs and the in-app stack frames. Match the frames to the services under src/app/features/article/services and src/app/core/auth/services, the interceptors under src/app/core/interceptors, and the article page component in src/app/features/article/pages/article. The project tests with Vitest through @analogjs/vite-plugin-angular: add a spec case beside the existing *.spec.ts that flushes the response the breadcrumbs show through HttpTestingController and reproduces the error, then fix the cause until `bunx vitest run` passes. Install with bun, run `bun run format:check` and `bun run build`, and the Playwright suite if its browsers install. Open a pull request that links the Sentry issue, quotes the frames and the failing spec 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 that changes one service, component or interceptor and adds a spec case next to it. The description links the Sentry issue, quotes the exception and the frames it followed, names the breadcrumb whose response it replayed through `HttpTestingController`, shows the spec failing before and passing after, and lists the format check and build with their results.

The session's transcript keeps the Sentry reads, each `bun` and `vitest` command with its full output and every file the agent opened, so a reviewer can see whether the Playwright run happened or why it was skipped. The `run.completed` webhook carries the agent's final message as `data.result` and a `session_url` for everything else.

Before merging, a reviewer checks that the flushed response is the one the breadcrumbs show, that a change in `errorInterceptor` or `UserService` does not stop a real 401 from logging the user out, and that `canModify` still compares usernames the same way. A follow-up message to the same session changes the approach on the same branch.

## Run it on every Sentry issue alert

Add an alert rule to the Sentry project with a webhook action and point it 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 redelivery returns the run that already started. One issue becomes one sandbox and one pull request.

Give the API key a webhook URL and Rush POSTs `run.completed` with `session_url` when the turn finishes, so the handler can comment the pull request link on the Sentry issue. The same handler can instead call a `webhook` trigger on an automation in the Project with this prompt, forwarding the alert's JSON as the body with the trigger's secret as `Authorization: Bearer`; Sentry signs its own webhooks and cannot send that header itself. 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?

An Angular error that depends on one API response is slow to chase by hand: you reconstruct the response from breadcrumbs, remember which interceptor rewrote the error before the component saw it, and run a jsdom suite that competes with your dev server. In a Rush sandbox the agent does that on its own disk with Bun and Vitest, keeps every command's output, and leaves your checkout untouched.

The pull request carries its proof, the spec that failed and now passes, and the transcript shows the format check, the build and the Playwright attempt behind it. Each issue runs separately, in parallel up to the key's `max_concurrent` limit, so the errors a release leaves across the article, profile and settings pages become small parallel reviews.

## Frequently asked questions

### Does it use Karma and Jasmine?

Not here: this repository moved its unit tests to Vitest through `@analogjs/vite-plugin-angular`, and the new spec uses Vitest's `describe` and `it` like the existing ones. In a project whose `test` script still runs `ng test`, the agent runs that script instead and writes the spec in the style the project already has.

### Will it change the interceptors for every caller?

Only when the frames point there, for example a 204 reaching the error normalizer with no body. Because every request passes through `src/app/core/interceptors`, the pull request flags such a change and the spec covers the exact response that broke, so a reviewer can ask for a narrower fix in a follow-up.

### What if the error is really the API's fault?

The breadcrumbs show the request and its status. If the backend returned a 500, the agent says so, proposes a change only where the front end should have handled that answer, and otherwise opens no pull request so the API team can take the issue.

### Does it run the RealWorld end-to-end specs?

When Chromium installs in the sandbox, yes: `bun run test:e2e` runs the shared specs from the `realworld` submodule against `ng serve` on port 4200 as `playwright.config.ts` sets up. The pull request says whether the suite ran.
