# Fix AWS CDK Errors from Sentry Alerts

Yes. An agent reads the Sentry event from a Lambda your CDK app deploys, reproduces it with Jest, fixes the handler or the stack, runs cdk synth and opens a PR.

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

## What the agent does

The agent reads the alert payload after the prompt, then opens the issue and its latest event through the Sentry connection. For a function deployed by CDK the useful fields are the exception and its frames, the function name and runtime tags Sentry's Lambda integration attaches, and the request id. A CDK app has two places a runtime error can come from: the handler code, or the infrastructure around it, such as a missing environment variable, a missing IAM grant that surfaces as `AccessDeniedException`, or a runtime the code does not match. The function name from the event is the key to both.

Then it reads the repository. In a repository shaped like aws-samples/aws-cdk-examples, every example is its own app: `typescript/api-cors-lambda-crud-dynamodb/package.json` pins `aws-cdk-lib` 2.262.1 and the `aws-cdk` CLI 2.1133.0 with `jest` 30, `@swc/jest`, `tsx` and TypeScript 7 as dev-dependencies, `cdk.json` runs the app with `npx tsc && npx tsx index.ts`, and there is no lockfile, so `scripts/build-typescript.sh` installs with `yarn install`, runs `build` and `test` if present, and calls `scripts/synth.sh`, which copies a fake `cdk.context.json`, sets `AWS_DEFAULT_REGION` to `us-east-1` and runs `cdk synth` with no account. The stack in `index.ts` makes one DynamoDB table named `items` with partition key `itemId`, five `NodejsFunction` constructs on `Runtime.NODEJS_24_X` from `lambdas/get-one.ts`, `get-all.ts`, `create.ts`, `update-one.ts` and `delete-one.ts`, each with `TABLE_NAME` and `PRIMARY_KEY` in `environment` and `grantReadWriteData` on the table, and a `RestApi` with `GET`, `POST`, `PATCH` and `DELETE` methods plus CORS `OPTIONS` from `addCorsOptions`. The handlers have their own `lambdas/package.json` with the v3 SDK clients, installed by the example's `postinstall` script.

The agent maps the function name in the event to its construct id, reads the handler, and writes the failing test first. The repository has two test shapes to follow. For handler code, a Jest unit test that imports the handler from `lambdas/` with the SDK client mocked and calls it with the event shape Sentry recorded, so a handler such as `get-one.ts`, which reads `event.pathParameters.id` without checking that `pathParameters` exists, fails the way the event describes. For infrastructure, an assertion test like `typescript/lambda-cron/lambda-cron.test.ts` or `typescript/ddb-stream-lambda-sns/test/ddb-stream.test.ts`: `Template.fromStack(stack)` with `hasResourceProperties` on `AWS::Lambda::Function` for `Environment.Variables` and `Runtime`, and on `AWS::IAM::Policy` with `Match.arrayWith` for the action the handler needs. An example with no `test` script gets a `jest.config.js` copied from `lambda-cron`, with the `@swc/jest` transform and `aws-cdk-lib/testhelpers/jest-autoclean` in `setupFilesAfterEnv`, and a `test` script in its `package.json`.

With the test failing for the event's reason, the fix goes to one place: the handler, or the construct in `index.ts` that was missing the grant, variable or runtime. The agent then runs `npm run build` for `tsc`, `npm test`, and `cdk synth` through `scripts/synth.sh` so the template still renders without credentials, and reads the synthesized template under `cdk.out` to confirm the policy statement or variable now appears. It changes nothing outside that example's directory, and if the example's snapshot tests use `normalizeTemplate` from `typescript/test-utils/normalize-template.ts`, it updates the snapshot only when the template change is the intended one and shows the diff in the pull request.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "A Sentry alert fired for a Lambda function deployed by this CDK application; its payload follows this prompt. Use the Sentry connection to read the issue and its latest event: the exception and its frames, the function name and runtime tags, and the request id. Find the CDK app the function belongs to (each example directory has its own package.json and cdk.json), map the function name to its construct in index.ts, and read the handler code it bundles. Write a failing Jest test first: a unit test of the handler with the AWS SDK client mocked and the recorded event shape, or an aws-cdk-lib/assertions test on the stack when the cause is a missing environment variable, IAM grant or wrong runtime. Add a jest.config.js and test script in the style of typescript/lambda-cron if the example has none. Fix the cause in the handler or the construct, not both unless both are wrong, and do not catch the exception to hide it. Run npm run build, npm test and cdk synth through scripts/synth.sh so the template renders with no AWS account. Open a pull request that touches only that example's directory, links the Sentry issue, quotes the event and the failing test output, and explains the cause. If it does not reproduce, stop and report what you tried.\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

What comes back is a pull request confined to one example directory: a handler file under `lambdas/` or the construct in `index.ts`, a new or extended test, and a `jest.config.js` and `test` script when the example had none. Its description links the Sentry issue, quotes the exception and frames, shows the test failing before the change and passing after, and gives the `tsc`, Jest and `cdk synth` output, with the relevant lines of the synthesized template when the fix was a grant or a variable.

A reviewer checks that the test reproduces the recorded event rather than a convenient one, that a new IAM statement is the narrowest action the handler needs rather than a wildcard, and that the synthesized template changed only where the description says. A `cdk synth` that passes with the fake context proves the app still renders; it does not deploy, so the reviewer deploys from their own pipeline after merging.

## Run it on every Sentry issue alert

Create an alert rule in the Sentry project that receives the Lambda's events, with a webhook action pointed at a handler on your server. Sentry signs its own requests and cannot add the `Authorization: Bearer` header a Rush `webhook` trigger requires, so the handler places the alert JSON after the prompt and sends this request with the Sentry issue id as `Idempotency-Key`, which makes a redelivered alert return the run already started.

Set a `webhook_url` on the API key and Rush POSTs `run.completed` with the `session_url` when the turn ends; the handler reads the pull request link from the session and comments it on the issue. Sentry groups one function's repeated crash into one issue, so one issue is one run.

## Why run it on Rush?

A Lambda bug lives at the join between code and infrastructure, and a laptop checkout shows one side at a time. The sandbox reads the handler, the construct and the synthesized template together, runs the handler under Jest with the SDK mocked, and renders the stack with `cdk synth` using the repository's own fake context, with no AWS credentials anywhere in the run.

The pull request carries its proof: the event the agent read, the test failing with that exception and passing after the change, and the template lines that now carry the grant or variable. Several alerts from several example apps run in several sandboxes at once, each installing only its own example's dependencies.

## Frequently asked questions

### Does the agent need my AWS account?

No. `scripts/synth.sh` copies a fake `cdk.context.json`, sets `AWS_DEFAULT_REGION` and runs `cdk synth`, which renders CloudFormation without calling AWS. Handler tests mock the SDK client. Nothing in the run deploys, and the pull request says so.

### Which side does it fix, the handler or the stack?

Whichever the event blames. A `TypeError` in handler frames is a handler fix with a unit test; an `AccessDeniedException` or an `undefined` environment variable read is a construct fix with an assertions test on the `AWS::IAM::Policy` or `AWS::Lambda::Function` resource. When both are wrong it changes both and says why.

### The example has no tests. Will it add Jest?

Yes, in the shape the repository already uses: a `jest.config.js` with the `@swc/jest` transform and `aws-cdk-lib/testhelpers/jest-autoclean`, as in `typescript/lambda-cron`, plus a `test` script in that example's `package.json`. The dev-dependencies are already listed there.

### What about snapshot tests?

An example with `__snapshots__` is updated only when the template change is the fix itself, such as a new policy statement, and the pull request shows the snapshot diff. The agent does not run `jest -u` to make an unrelated difference go away.

### Does it work for Python, Java, Go or C# CDK apps?

The approach does: map the function to its construct, reproduce with that language's test runner, fix, synth. The commands differ, and this page's request names the TypeScript tooling. For a Python app, name `pytest` and the assertions module in the prompt.
