Appearance
Fix common agent problems
Start with three checks:
- Run
agent-sdk validate --dir .. - Confirm the expected agent and connections in
agent-sdk info --dir . --json. - 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. |
| 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. |
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. |
| 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 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. |
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 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. |
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. |
| 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. |
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 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 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 Add Slack wizard after an admin approves. See Slack. |
| 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 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. See Host MCP OAuth. |
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 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.
Related
- Deployment: hosted and self-hosted boundaries
- Sessions: session ownership and event vocabulary
- CLI reference: command flags and exit behavior