@cursor/sdk 1.0.28 local send() dies after ~1h idle with “log out and back in”; same API key works only after Node restart

Where does the bug appear (feature/product)?

Cursor SDK

Describe the Bug

Long-lived Node host (@cursor/sdk 1.0.28, Windows) with a valid CURSOR_API_KEY passed into Agent.create / Agent.resume.

Observed window

  • Idle under ~1 hour: dispose + Agent.resume / in-process retry often recovers.
  • Idle over ~1 hour: every in-process method fails (reload(), dispose + resume, retry send()). Only restarting the Node process restores the same API key and the same sdk_agent_id. Then it is healthy for about another hour.

The user-facing text is:

Authentication error
If you are logged in, try logging out and back in.

That copy is for the Cursor IDE session. This host is not using IDE login. Cursor.auth.login() / logout() only mint/clear ~/.cursor/sdk/auth.json and do not fix it.

Cursor.me({ apiKey }) still works while send() is dead. Same key works immediately after process restart. Looks like the short-lived token the SDK exchanges from the API key cannot be refreshed in-process after ~1h.

Still broken vs confirmed threads:

Steps to Reproduce

  1. Node 22+, Windows, @cursor/[email protected], CURSOR_API_KEY set.

  2. Keep a live handle:

const agent = await Agent.create({
  apiKey: process.env.CURSOR_API_KEY!,
  model: { id: "composer-2.5" },
  local: { cwd: "C:\\path\\to\\repo" },
});
await agent.send("hello");
  1. Idle under 1 hour, then send() again. Often recoverable with:
await agent.close();
const resumed = await Agent.resume(agent.agentId, {
  apiKey: process.env.CURSOR_API_KEY!,
  model: { id: "composer-2.5" },
  local: { cwd: "C:\\path\\to\\repo" },
});
await resumed.send("hello again");
  1. Idle over 1 hour, then send() again. Terminal AuthenticationError:
Authentication error
If you are logged in, try logging out and back in.

agent.reload(), close() + Agent.resume, and retries all fail.

  1. Restart the Node process. Agent.resume the same agentId with the same API key. Works for about another hour, then repeats.

Expected Behavior

After idle, the SDK should re-exchange the API key on the same Node process, or return a retryable error (NetworkError / isRetryable: true) so the host can:

await agent.close();
const resumed = await Agent.resume(agentId, { apiKey, local: { cwd } });

without restarting the process.

It should not surface a terminal AuthenticationError with IDE copy:

If you are logged in, try logging out and back in.

API-key hosts (CURSOR_API_KEY / explicit apiKey) are not logged into the Cursor IDE. Cursor.auth.login() / logout() only touch ~/.cursor/sdk/auth.json and are not a fix.

In this environment the hard latch is ~1 hour, not ~15 minutes. After that, only a full Node process restart restores the same key and the same agentId.

Operating System

Windows 10/11

Version Information

Not the Cursor IDE. This is the TypeScript SDK in a long-lived Node process.

@cursor/sdk: 1.0.28
Node: 24.13.1
OS: Windows 11 (10.0.26200)
Runtime: local Agent.create / Agent.resume
Host: HTTP service holding live SDKAgent handles for hours

For AI issues: which model did you use?

Reproduced with:

  • composer-2.5 (fast=false)
  • grok-4.6

The failure is on agent.send() before a model turn. Same for both.

Additional Information

Credential setup:

  • apiKey is passed explicitly (CURSOR_API_KEY).
  • Not using Cursor IDE login.
  • Cursor.auth.login() / logout() only mint/clear ~/.cursor/sdk/auth.json. They do not refresh the in-process exchanged token and do not fix this.

Workarounds tried (over 1h idle):

  • in-process retry of send()
  • agent.reload()
  • close() + Agent.resume(agentId) with the same key and cwd

All fail. Restarting the Node process restores the same key and the same agentId for about another hour.

Under ~1 hour idle, resume often recovers.

Related (still open):

WARN: run ended in error: Authentication error If you are logged in, try logging out and back in.
jobId: “job_dc44235c-…”
runId: “run-f50ada83-…”
terminalStatus: “error”
sdkStatusMessage: “Authentication error If you are logged in, try logging out and back in.”
runResultDetail: null
streamThrew: null

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

We do not have @cursor/sdk source. The npm 1.0.28 package is minified. What follows is a suspicion from public .d.ts / .d.ts.map paths and one webpack chunk (dist/esm/357.js), not a confirmed patch site. Please treat the file names as leads.

What we think is happening

  1. src/agent/executor-common.ts (from executor-common.d.ts.map) exports:

    • exchangeApiKeyForAccessToken
    • buildTransport
    • createRetryingAgentClient(initialClient, refreshClient)

    Hypothesis: the user API key is exchanged once into a short-lived Bearer on the Connect/HTTP2 client. After ~1h that Bearer is dead. refreshClient looks like the intended rebuild path, but it does not seem to run for this failure (process restart, which builds a new client, immediately works with the same API key).

  2. Error classification in minified dist/esm/357.js (agent-core / aiserver/v1 proto ErrorCode): a set including NOT_LOGGED_IN, AUTH_TOKEN_EXPIRED, UNAUTHORIZED is treated as ActionRequiredError / action "login". Connect Unauthenticated is mapped the same way. Concatenating ErrorDetails title + detail matches our log:

    Authentication error If you are logged in, try logging out and back in.
    

    Hypothesis: enableAgentRetries only retries transport/RetriableError, so this class is skipped. We could be misreading minified control flow.

  3. src/agent/errors.tsconvertConnectErrorAuthenticationError. Likely where the public typed error is produced. Unconfirmed whether the chat status.message is this class or the proto details only.

  4. SDKAgent.reload() / src/agent/local-executor.tsreload() did not recover for us. We suspect it reloads workspace, not exchangeApiKeyForAccessToken. Not verified in source.

What we actually observed (solid)

  • @cursor/[email protected], Windows, explicit CURSOR_API_KEY.
  • Idle < ~1h: close() + Agent.resume often works.
  • Idle > ~1h: reload(), resume, retries fail; Node process restart restores the same key / same agentId for ~another hour.

We first hit this on 1.0.18 (June 2026) and have since tried 1.0.22, 1.0.26, and 1.0.28. Same latch every time. login / reload / getUsage in later versions did not change it.

Also tried, no effect: Agent.close() + Agent.resume after ~1h idle, agent.reload(), Cursor.auth.login() / logout(), Cursor app logout. Same API key keeps working after a Node process restart, then dies again after about an hour.

Hi @RGU, thank you for the detailed report. This is not your API key, not quota, and not an IDE login problem. Cursor.auth.login() / logout() only touch ~/.cursor/sdk/auth.json, so they cannot recover a host that already passes CURSOR_API_KEY. The “log out and back in” copy is the wrong advice for that setup.

This is an issue we are tracking. After about an hour idle, local send() fails with that authentication error even though the same API key is still valid. That is why Cursor.me({ apiKey }) keeps working, while reload(), in-process retries, and close() plus Agent.resume() do not. Restarting the Node process restores the same key and the same agentId.

Until this is addressed, keep using the recovery you already found: restart the Node process, then Agent.resume the same agentId. For a long-lived host, recycle the process before that ~1 hour window, or as soon as you see this authentication error.

I will post here when there is an update.

For a long-lived host, I’d want the SDK to make this boundary explicit: refresh the exchanged token in process, or return a retryable error that says whether the same agent occurrence was resumed. The current AuthenticationError mixes credential failure with expired session state. Persisting the last acknowledged event before recycling the process would also make recovery less ambiguous.

Hey @joinwell52 @RGU

This should be fixed in v1.0.29 of the Cursor SDK which has been published. Give it a try!

I’m still seeing the same issue.
I created a brand new session this morning after upgrade to new version.
the last msg was at 08:57
I let it sitting for a while, send a new msg on 11:08
Get back
Reason: Authentication error If you are logged in, try logging out and back in..11:09

tried a few times, same as before.


8:57:12 AM

status: finished

11:08:53 AM

status: running

11:09:06 AM

status: error

11:09:10 AM

status: running

11:09:10 AM

status: error

11:09:19 AM

status: running

11:09:19 AM

status: error

Hey @RGU, thanks for checking so quickly, and sorry for the confusion here.

It turns out the change just missed the 1.0.29 release cut, so 1.0.29 behaves the same as 1.0.28 for this.

Version 1.0.30 of @cursor/sdk is now published and does contain the change: the SDK refreshes the exchanged token shortly before it expires and recovers in-process, so a long idle should no longer require a Node restart.

Please upgrade to 1.0.30, start a fresh session, and let it idle past the hour mark again. If it still reproduces on 1.0.30, post the timestamps here and we will dig back in!

Thanks @Colin ! Great work Cursor Team!

I can confirm it’s working correctly now.

12:57:52 PM

status: running

12:58:03 PM

(thinking) Acknowledging the ping.

12:58:03 PM

(thinking)

12:58:03 PM

Still here. Job is open — say what you need.

12:58:04 PM

status: finished

4:20:21 PM

status: running

4:20:32 PM

(thinking) The user sent a simple

4:20:32 PM

(thinking) check-in ping.

4:20:32 PM

(thinking)

4:20:32 PM

Yes — still here, job is open.