# Fix common agent problems

Start with three checks:

1. Run `agent-sdk validate --dir .`.
2. Confirm the expected agent and connections in
   `agent-sdk info --dir . --json`.
3. Reproduce once, then inspect the serve log or session trace.

Match the visible symptom below.

## Serve or the playground will not work

| What you see | What to do |
| --- | --- |
| `serve` exits before listening | Fix the errors from `agent-sdk validate --dir .`, then start it again. |
| Playground is blank or says there are no agents | Start `agent-sdk serve`; built playground assets have no agent data without the server. |
| Agent-file edits do not appear | Open the URL printed by `serve --dev`, then press Enter in its TTY to reload after file changes. |
| Sessions exist but the list is empty | The list is scoped to the authenticated principal. Use the same identity that created the session; a `?sessionId=` deep link does not bypass authorization. |
| The preferred port is busy | Use the next port printed by the CLI, pass `--port <number>`, or pass `--port 0` for any free port. |

## A model turn fails

| What you see | What to do |
| --- | --- |
| File reads and greps fail repeatedly with `NGHTTP2_FRAME_SIZE_ERROR` | Run the agent under Node 22.13 or newer, never Bun. |
| `Semantic search has been removed. Use Grep.` | Delete `search` from a custom `fs`, drop `SearchQuery` and `SearchResult`, and remove `SemanticSearch` or `semSearch` from `tools` and `bot/tools/`. See [Migrate off semantic search](/docs/reference/agent-config.md#migrate-off-semantic-search). |
| The turn immediately reports a missing API key | Set `CURSOR_API_KEY`, `CURSOR_API_KEY_FILE`, or `CURSOR_SERVICE_ACCOUNT_KEY`, or run `agent-sdk login`. |
| Login succeeds but the model host rejects the key | Point login and model traffic at the same API host; check `CURSOR_API_BASE_URL` and `CURSOR_BACKEND_URL`. |
| The first turn reports `[resource_exhausted]` | Treat it as a capacity-shaped error. For a GitHub wake, also check the connected GitHub credential and any GitHub `429` rate limit before assuming the model quota is exhausted. |

## A turn behaves unexpectedly

| What you see | What to do |
| --- | --- |
| Replies quote an ancestor `AGENTS.md` or unrelated repository rules | Inspect `local.cwd` in `/v1/info`. Set `defineAgent({ local: { cwd } })` or the session workspace explicitly instead of inheriting the parent checkout. |
| The model lists IDE meta-tools but never calls named MCP tools | Set `advertiseTools: true` on the local model-visible connection and confirm it under `connections` in `/v1/info`. |
| Server tools, skills, or seed files are absent | Check the discovered project in `/v1/info`; follow the capability warning from `validate`. |
| `validate` and `run` pass but CI type-checking fails | Run the project type check. Tool results must be JSON-shaped; prefer object literals or `type` aliases over `interface` return types. |

## HTTP returns 401, 403, or 409

| What you see | What to do |
| --- | --- |
| `401` outside local development | Send the configured bearer token, alias token, or channel credential. Default custom routes admit direct loopback only. |
| `403` on a stream or follow-up | Use the same authenticated principal that created the session. |
| A custom channel route fails through a tunnel or LAN | Protect the shared host with `--bearer-token` or authored channel auth. Use `--allow-anonymous` only behind a proxy that authenticates every caller. |
| `409` on a follow-up | Refresh the rotating `continuationToken` and confirm the target is a chat session; task sessions do not accept follow-ups. |
| `409 session_busy` from `call --session` | Wait for the turn, omit `--session`, or mark a read-only tool with `effect: "read"` so it can run concurrently. |
| A custom route fails schema type-checking | Add the required Zod `querySchema` for `GET`, or `bodySchema` for `POST`, `PUT`, and `PATCH`. See [Channels](/docs/reference/channels.md). |

## A hosted deployment fails or looks stale

| What you see | What to do |
| --- | --- |
| `validate` or `deploy` reports `architecture "v2" requires a named secret` | A `githubChannel` credential or a GitLab or Bitbucket `webhookSecret` is a literal or a getter. Replace it with the quoted `{ secretName: "NAME" }` and set the value with `agent-sdk secret set <slug> NAME`. See [Other hosts](/docs/guides/github.md#other-hosts). |
| Local changes do not appear after deploy | `deploy` reads a pushed Git ref, not the working tree. Commit and push the intended ref, then deploy it again. |
| The deployment never becomes running | Run `agent-sdk deployment get <slug>`, then act on the reported build or startup error. |
| A secret or egress change has no effect | Confirm the name with `secret list`, verify the `hosting` block exists on the pushed ref, and follow the CLI or [Deployed Agents](https://cursor.com/dashboard/deployed-agents) prompt to redeploy. |
| `agent-sdk deploy` blocked by team egress policy | Add the named hosts to the team egress list, or remove them from `hosting.egressDomains`, then run `agent-sdk deploy` again. The bot that is running now keeps its last deployed policy. |
| Cursor events stopped after redeploy | Each redeploy replaces the watched repositories. Pass every `--cursor-events-repo` value again; without the flag, the deployment watches only its GitHub source repository. |
| `session create` prints a `deliveryId` but no `sessionId` | Expected without `--wait`: the session is created when the turn starts. Pass `--wait`, or find it with `agent-sdk logs --prod --once --slug <slug>`, then follow [Verify a hosted turn](/docs/deployment.md#verify-a-hosted-turn). |
| `session get <sessionId> --prod` shows a `running` run with no logs | Runs lag behind events, and a high-effort turn can take several minutes. Rerun the command; a growing event count means the turn is still working. |
| A [Deployed Agents](https://cursor.com/dashboard/deployed-agents) link to a single session doesn't open | Check the session with `agent-sdk session get <sessionId> --prod --slug <slug>`. |
| `chat`, `tool call`, `skill`, `session get --view cost`, or `mcp` with `--prod` exits with a usage error | Hosted deployments take `--prod` only on `session list`, `session get`, and `logs`; `session create` is always hosted. See [Verify a hosted turn](/docs/deployment.md#verify-a-hosted-turn). |
| `session create --session <sessionId>` reports the session belongs to another channel | `--session` continues only sessions that `session create` started. Reach Slack, SCM, and custom-route sessions through their own channel. |
| A custom route returns `202` with no body | Expected on managed hosting. The handler runs after the response, so deliver results from the channel. See [Route responses](/docs/reference/channels.md#route-responses). |
| External HTTP rejects the alias token | Update the caller with the current token. If the token is lost or exposed, run `agent-sdk deployment rotate-token <slug>` and replace it everywhere. |
| `deploy`, a hosted session, or an eval run says it is not available with Privacy Mode (Legacy) | Switch to Privacy Mode, or ask a team admin if your team enforces this setting. A refused session does not store the message. See [Privacy Mode](/docs/deployment.md#privacy-mode). |
| `deploy` says persistent deployments are limited to 1 per team | Another deployment of the team already sets `persistent: true`. Remove the setting from one agent, or delete that deployment. |
| A schedule does not fire on the hosted deployment | Make sure the deployment is running and its release has the schedule. Deploy again with `@grok/agent-sdk` 0.2.14 or newer. |
| A request to a custom route gets `429` | The deployment received more requests than its limit. Wait for the time in `Retry-After`, then send the request again. |

See [Deployment](/docs/deployment.md) for source, credential, and
redeployment boundaries.

## GitHub deliveries fail

| What you see | What to do |
| --- | --- |
| `github forward` returns 401 on every delivery after creating the hook | Clear `GITHUB_TOKEN` and `GH_TOKEN` for that command so the forwarder uses the `gh` CLI login: `GITHUB_TOKEN= GH_TOKEN= agent-sdk github forward ...`. |
| `Hook already exists` | Run one forwarder for the repository and stop the stale process. |
| Direct webhook deliveries are rejected outside `--dev` | Configure the same `GITHUB_WEBHOOK_SECRET` on the signer and server. Cursor event pull needs no public webhook or webhook secret. |
| You cannot create a forwarder | Use `agent-sdk github replay <pr-url>`; it needs pull access instead of repository administration. |

The [GitHub guide](/docs/guides/github.md) covers event pull, replay, and
direct webhooks.

## Slack does not respond

| What you see | What to do |
| --- | --- |
| Logs say `channel idle ... missing credentials` | Run `agent-sdk slack create --dir <agent>`, then check the generated prefix with `agent-sdk slack doctor`. Use `slack init --manual` only for an app you own. |
| `slack create` is waiting for workspace approval | Keep the CLI running, open the **Request approval** link it prints, and select **Retry** in the [Deployed Agents](https://cursor.com/dashboard/deployed-agents) **Add Slack** wizard after an admin approves. See [Slack](/docs/guides/slack.md#connect). |
| The bot ignores ordinary channel posts | Configure `engagement.channelPosts`, create the app with `--channel-posts`, and invite it to every allowed channel. |

See the [Slack guide](/docs/guides/slack.md) for app setup and engagement
choices.

## MCP authorization fails

| What you see | What to do |
| --- | --- |
| `must be defineConnection({ url, oauth: true })` | Add `oauth: true` to the named URL connection or correct the connection filename passed to `mcp oauth`. |
| Local auth works but hosted calls return unauthorized | Locally stored OAuth tokens don't reach a deployment. Use a `cursorAccount: true` connection and connect the server from [Deployed Agents](https://cursor.com/dashboard/deployed-agents). See [Host MCP OAuth](/docs/guides/mcp-oauth.md#use-an-oauth-server-from-a-hosted-agent). |
| The model invents `mcp_auth` instead of calling the server | Set `advertiseTools: true` for named local tools, or expose a host-side wrapper through `ctx.host.mcp`. |

See [Host MCP OAuth](/docs/guides/mcp-oauth.md) for the credential lifecycle.

## Schedules or reminders stall

| What you see | What to do |
| --- | --- |
| A schedule or reminder never fires under `--dev` | Trigger it through the matching `/v1/dev/schedules/<id>` or `/v1/dev/reminders/<id>` route; development mode does not auto-fire. |
| A reminder is disarmed with `handler_lost_on_restart` | Recreate handler-form reminders after restart, or use a prompt-form reminder. |
| The same schedule fires on several self-hosted processes | Enable schedules on one serving process per project and pass `--no-schedules` to the others. |

## A credential was exposed

| What you see | What to do |
| --- | --- |
| A secret value appears in a command, transcript, or shell history | Rotate it at the provider, set it again through hidden input or stdin, and test the feature. |
| An alias token appears outside its secure destination | Run `agent-sdk deployment rotate-token <slug>`, store the new value outside transcripts, and update every caller. |
| Someone printed a secret to verify it | Rotate it. Confirm only the name with `agent-sdk secret list <slug>`, then redeploy and exercise the feature. |

## Read the session trace

Start with `actions.requested` and `action.result`. Count calls by tool
name, pair every request with its result, and separate host preparation
from tools chosen by the model.

`turn.failed` with `turn interrupted` usually means a follow-up or stop
ended the turn deliberately. Other failures should have an error event
near the tool or model boundary that produced them.

Use the trace path printed by `agent-sdk run`:

```text
agent-sdk session get --file <trace-path>
```

The playground's **Open trace** control renders the same trajectory.
When the agent runs but makes poor decisions, move from diagnosis to a
measured [hillclimb](/docs/hillclimbing.md).

## Related

- [Deployment](/docs/deployment.md): hosted and self-hosted boundaries
- [Sessions](/docs/reference/sessions.md): session ownership and event
  vocabulary
- [CLI reference](/docs/reference/cli.md): command flags and exit behavior
