Where does the bug appear (feature/product)?
Cursor SDK
Describe the Bug
We run a long-lived Node.js HTTP service that wraps @cursor/sdk for platform automation (Background Agents API, local runtime). After the process has been idle for a while (~15+ minutes), agent.send() fails with an opaque bare status=ERROR — the stream and run.wait() return no message, code, or error fields — in ~270 ms with zero streamed output (streamChars=0, events=2).
Restarting the host Node process immediately fixes it with the same API key and the same model: { id: "auto" }. This is not a usage/quota issue: Cursor.me({ apiKey }) succeeds before every failed send, and the same key works right after restart without any quota reset.
Sometimes the underlying cause leaks as process.on('unhandledRejection') → ConnectError: [unauthenticated] Error, but it is not catchable in our send() / stream() / wait() chain.
Steps to Reproduce
-
Install and use
@cursor/[email protected]on Node.js 22.x (Windows 10). -
Create a local agent and verify the API key:
import { Agent, Cursor } from "@cursor/sdk";
await Cursor.me({ apiKey: process.env.CURSOR_API_KEY! }); // succeeds
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "auto" },
local: { cwd: "/path/to/repo" },
});
-
Leave the Node process idle for ~15+ minutes (or reuse a cached agent handle after idle).
-
Call:
const run = await agent.send("hello", { model: { id: "auto" } });
for await (const event of run.stream()) {
if (event.type === "status" && event.status === "ERROR") {
console.log("bare ERROR:", JSON.stringify(event));
}
}
const result = await run.wait();
console.log(result);
-
Observe instant failure (~270 ms, no assistant output).
-
(Optional confirmation) Kill and restart the Node process, repeat step 4 with the same API key — run succeeds with normal streaming.
Minimal repro script (save as repro-bare-error.mjs):
import { Agent, Cursor } from "@cursor/sdk";
const apiKey = process.env.CURSOR_API_KEY!;
const cwd = process.cwd();
await Cursor.me({ apiKey });
const agent = await Agent.create({
apiKey,
model: { id: "auto" },
local: { cwd },
});
console.log("Agent created:", agent.agentId);
console.log("Idle this process for 15+ minutes, then press Enter to send...");
await new Promise((resolve) => process.stdin.once("data", resolve));
const run = await agent.send("Say hello", { model: { id: "auto" } });
for await (const event of run.stream()) {
console.log("stream:", JSON.stringify(event));
}
console.log("wait:", await run.wait());
Expected Behavior
-
run.wait()should reject with a typedAuthenticationError(or return a result that includescode,message, andisRetryable: true). -
When the idle local-agent gRPC access token expires, the SDK should either transparently reconnect or surface a retryable error so host apps can
agent.close()+Agent.resume(agentId)without restarting the whole process. -
Bare
{ status: "error" }with no payload should not be the only signal — it makes quota limits, transport lapses, and agent-busy states indistinguishable.
Operating System
Windows 10/11
Version Information
@cursor/sdk: 1.0.22
@cursor/sdk-win32-x64: 1.0.22
Node.js: 22.x
Host: Code Worker Agent (HTTP wrapper around Background Agents API, local runtime)
Integration: Agent.create() + agent.send() + run.stream() + run.wait()
For AI issues: which model did you use?
Model: { id: "auto" } (server-routed Auto)
Failures also occur when the resolved wait result shows "model":{"id":"default"}.
For AI issues: add Request ID with privacy disabled
Example request IDs from the 2026-07-06 incident (8 consecutive bare failures, all instant):
requestId=4edc81ca-6ad5-41c0-993a-3332e788ae20
requestId=5e800d87-67e4-45eb-8866-abe9790cf51f
requestId=9aa5a9c9-9084-4b12-8ede-4bbd2306b2c4
requestId=53628817-0c39-4a3b-ad73-ad2854a221b6
requestId=788bb2c1-d663-481e-830d-9731fb38d2e7
Example agent/run IDs from the same session:
agent_id=agent-84dcd591-2b7c-4d62-af8a-5b6d5005528e
run_id=run-ea041a38-9ad5-47f7-bfdd-69e6739fc1f6
Additional Information
On 2026-07-06:
- Cursor Usage dashboard: API 100%, Auto 86% (misleading — restart fixed runs without quota reset).
- 8 consecutive runs failed in ~90 seconds (08:52–08:53), all
model=auto. - Manual Node process restart at 09:11 → success at 09:12, same key, same model.
Cursor.me({ apiKey })succeeded on every attempt beforesend().
If this were true quota exhaustion, restarting the local process would not help.
Workaround (confirmed by Cursor staff in #161203 / #163819)
await agent.close?.();
const fresh = await Agent.resume(agentId, {
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "auto" },
local: { cwd: "/path/to/repo" },
});
// Retry send on `fresh` — usually succeeds immediately
Does this stop you from using Cursor
No - Cursor works, but with this issue