# @cursor/sdk local agent: named models fail with status: "error" and no error message

**URL:** <https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248>\
**Category:** Bug Reports\
**Tags:** cursor-sdk, composer\
**Created:** [June 28, 2026, 5:06pm UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248 "2026-06-28T17:06:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Parthiv\_Shah](https://avatars.discourse-cdn.com/v4/letter/p/9fc348/32.png) [@Parthiv\_Shah](https://forum.cursor.com/u/Parthiv_Shah)\
**Post date:** [June 28, 2026, 5:06pm UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/1 "2026-06-28T17:06:40Z")

</div>

Hi Cursor team,

I’m building a headless app using `@cursor/sdk` (local runtime). `Cursor.models.list()` returns the full catalog (~30 models) with parameters and variants, but **any explicitly named model fails at run time**. Only `default` / `auto` completes successfully.

This happens with BYOK disabled and no custom API keys on the account, just a standard Cursor user API key from the dashboard.

| | |
| --- | --- |
| SDK | @cursor/sdk@1.0.22 |
| BYOK | Disabled |
| Runtime | Local (local: { cwd, settingSources: }) |
| Custom provider keys | None on account |
| Auth | User API key (CURSOR\_API\_KEY from Cursor Dashboard → API Keys) |
| Node | v22.19.0 |

Minimal repro (no MCP, no custom tools, no project settings):

```auto
import { Agent, Cursor } from "@cursor/sdk";

const apiKey = process.env.CURSOR_API_KEY!;

// Step 1: catalog works — returns 30 models including composer-2.5, claude-sonnet-4-6, etc.
const models = await Cursor.models.list({ apiKey });
const composer = models.find((m) => m.id === "composer-2.5");
// composer.parameters includes { id: "fast", values: ["false", "true"] }
// composer.variants includes isDefault: true with params: [{ id: "fast", value: "true" }]

// Step 2: named model fails
const agent = await Agent.create({
  apiKey,
  model: {
    id: "composer-2.5",
    params: [{ id: "fast", value: "true" }], // catalog default variant
  },
  local: { cwd: process.cwd(), settingSources: [] },
});

const run = await agent.send("Reply with exactly: ok");
const result = await run.wait();
// result.status === "error"

```

Same failure with:

- `{ id: "composer-2.5" }` (no params)
- Default variant params from `variants.find(v => v.isDefault)`
- Other models: `claude-sonnet-4-6`, `gpt-5.4-mini`, `claude-opus-4-6`
- Both minimal config (`settingSources: []`) and full bot config (`settingSources: ["project"]`, MCP, custom tools)

**What works:**

```auto
model: { id: "default" } // ✅ status: "finished"
model: { id: "auto" } // ✅ resolves to default, status: "finished"

```

* * *

## **What happens**

1. `Agent.create()` succeeds — agent ID is assigned (e.g. `agent-80704988-...`).

2. `agent.send()` succeeds — run ID and `requestId` are returned.

3. Stream emits:

4. `run.wait()` resolves with:

5. `run.conversation()` returns `[]` (empty — no assistant text, no error detail).

6. **No exception is thrown** — this is a run-level failure, not a `CursorAgentError` startup failure.

* * *

## **Error codes / identifiers**

There is **no HTTP status code or error message** in the response. What we do get:

| Field | Example value |
| --- | --- |
| `run.status` | `"error"` |
| Stream `status` | `"ERROR"` (after `"RUNNING"`) |
| `run.requestId` | `f6ff0b72-9585-4278-9aa8-31b237362eb0` |
| `run.id` | `run-b397e483-32eb-4c57-935a-c3a82282f107` |
| `agent.agentId` | `agent-80704988-2991-41cd-957e-df710d01fa79` |
| `result.result` | `undefined` |
| `run.conversation()` | `[]` |

No `CursorAgentError` is thrown. No message like “model not available” or “unsupported model” appears in the stream or `RunResult`.

* * *

## **What I’ve ruled out**

- **Missing `model.params`** — docs say parameterized models need explicit params; I pass the catalog default variant (`fast: true` for composer-2.5). Still fails.
- **BYOK / custom keys** — disabled and confirmed none on account.
- **Wrong model ID** — IDs match `Cursor.models.list()` exactly; aliases also tried.
- **Local config pollution** — fails with `settingSources: []` (no project/user settings loaded).
- **SDK version** — reproduced on `@cursor/sdk@1.0.22`.

Has anyone else experienced this? If so, were you able to identify the cause or find a workaround?

Thanks!

---

<div class="post-metadata">

**Author:** ![Jason\_Luo1](https://avatars.discourse-cdn.com/v4/letter/j/bc79bd/32.png) [@Jason\_Luo1](https://forum.cursor.com/u/Jason_Luo1)\
**Post date:** [June 29, 2026, 1:59pm UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/4 "2026-06-29T13:59:29Z")

</div>

The missing error message is probably the biggest issue here.

If the catalog returns those named models, the SDK user will assume they are valid inputs. When the run only returns status error, it becomes hard to tell whether the problem is auth, model routing, params, local runtime, or account eligibility.

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [July 1, 2026, 1:36pm UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/6 "2026-07-01T13:36:43Z")

</div>

Hey, thanks for the detailed report. The request ID and steps really helped speed up the investigation.

Main point: this isn’t a bug in specific models. From your request ID, we can see the named models are being rejected with HTTP 429 usage limit, not with a model unavailable type error. When your account goes over the included usage limit, Cursor limits agent requests to Auto default only. That’s why default auto works, but any explicitly named model composer-2.5, claude-_, gpt-_ returns 429.

The part where you get a vague status error with an empty conversation is a known gap in the SDK. run.wait currently doesn’t surface stream errors, and RunResult doesn’t have an error field, so the 429 never reaches you. We’ve logged an issue for this, but I can’t share an ETA yet. And yes, Jason\_Luo1 is right, the swallowed error message is the biggest pain here.

What you can do right now:

- Use default auto, it will resolve to an allowed model
- Wait for the included usage window to reset, you can check status in the dashboard
- Turn on usage-based pricing or upgrade for more included usage

Named models will work again as soon as you’re back under the limit. Let me know if it still happens after the limit resets, and we’ll dig deeper.

---

<div class="post-metadata">

**Author:** ![JeremyChow](https://avatars.discourse-cdn.com/v4/letter/j/5e9695/32.png) [@JeremyChow](https://forum.cursor.com/u/JeremyChow)\
**Post date:** [July 3, 2026, 5:32am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/8 "2026-07-03T05:32:00Z")

</div>

> [@Parthiv\_Shah](#):
>
> his happens with BYOK disabled and no custom API keys on the account, just a standard Cursor user API key from the dashboard.

I met the same problem, cursor sdk should have more useful response message to help us solve the problem.

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [July 3, 2026, 8:04am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/9 "2026-07-03T08:04:22Z")

</div>

Hey @JeremyChow, thanks for following up. Just seeing `status: "error"` with no details is a known gap in the SDK. `run.wait()` doesn’t currently surface the stream error, so the real reason never reaches you. We’re working on better error messaging, but I can’t share an ETA yet.

That said, a bare error almost always hides a specific server-side reason. For the thread author, it turned out to be an HTTP 429 usage limit. Once you exceed included usage, agent requests are limited to Auto `default` only, so any named model fails.

To figure out if that’s what’s happening for you or if it’s something else like auth, params, or environment, can you share:

- which SDK and version you’re using TS `@cursor/sdk` or Python `cursor-sdk`
- the Request ID from the failed run `run.requestId`
- whether `model: { id: "default" }` or `"auto"` works for you

With the Request ID, we can check exactly why the server rejected the request and give you a more precise answer.

---

<div class="post-metadata">

**Author:** ![nkoynov](https://avatars.discourse-cdn.com/v4/letter/n/5f9b8f/32.png) [@nkoynov](https://forum.cursor.com/u/nkoynov)\
**Post date:** [October 7, 2026, 5:25am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/10 "2026-10-07T05:25:44Z")

</div>

An update for the error-messaging work, from local `@cursor/sdk` runs: `run.wait()` now returns `RunResult.error` (we see it in 1.0.31 and later), which helps a lot. In every failed run we have, though, `error.code` is unset and the status sits inside `error.message`:

| `error.message` | Request IDs |
| --- | --- |
| `[resource_exhausted] Error` | `455f7421-d101-4dff-9d66-91603763e30e` |
| `[unknown] [canceled] This operation was aborted` | `19c2ee4e-d757-4e7e-af57-19257f5ad2eb`, `86c4ab29-9af8-4b3f-8a47-3f8a6c2816d8`, `6edebb07-c98b-4b0e-8688-4da3d64cd9cc` |
| `Agent turn stopped after repeated resume attempts made no progress` | `d33c41ce-a4e9-4de0-beea-63f6bfdc8607` |

All five were local runs of `claude-opus-5-5` on 2026-10-04/05, made with privacy mode on.

In 1.0.35 and 1.0.36, when a run ends with an error recorded in the local run store, the SDK copies that string as-is: `void 0===this._error&&t?.errorCode&&(this._error={message:t.errorCode})` (`dist/cjs/index.js`). Errors thrown from the stream go through a helper that already splits `[code] message` into `{ code, message }`. Sending the stored string through the same helper would fill `code` for runs like these.

Beyond that, it would help to get the retry delay when the server has one, and to know whether a `canceled` came from the server or the client.

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [October 12, 2026, 10:51am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/12 "2026-10-12T10:51:34Z")

</div>

Thank you for the detailed update and for the code analysis. It really helps.

Just to confirm: the fact that in 1.0.31+ `run.wait()` now returns `RunResult.error` is expected and comes from the work to better surface errors. What we are still tracking is that `error.code` stays empty, while the real status like `[resource_exhausted]`, `[canceled]`, and so on is still inside `error.message`. We’ve already logged an update for this thread.

Your suggestion to run the saved string from the local run store through the same helper that already parses `[code] message` into `{ code, message }` has been passed to the team. I also passed along two extra requests: returning the retry delay when the server sends it, and distinguishing whether `canceled` came from the server or the client. I can’t give an ETA yet.

One small clarification on your table: those five messages actually mean different things under the hood. `[resource_exhausted]` is a usage limit rejection, while `[canceled] This operation was aborted` and `Agent turn stopped after repeated resume attempts` refer to other scenarios. A properly populated `error.code`, and where available request ID plus retry delay, should help distinguish them programmatically. I also grabbed the request IDs you shared for investigation.

If after the SDK update you still see that `error.code` is empty, write back and we’ll take another look.

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [October 21, 2026, 5:31am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/14 "2026-10-21T05:31:15Z")

</div>

Hey @nkoynov, do you have an update on the empty `error.code`?

We shipped a fix for failed local runs. After this, `RunResult.error` will return both `code` like `resource_exhausted` and `message`. This applies to `wait()`, `Agent.getRun`, and `Agent.listRuns`. Runs that are already saved in the local store in the `[code] message` format will also get `code` when read.

This fix is not yet in the current latest version of `@cursor/sdk` 1.0.40. I’ll post here when a version with it is out.

The server retry delay and the distinction between server and client `canceled` were not included in this change. Those requests are still being tracked separately by the team.

When you update, could you please check it? If `code` is still empty, post here and include the Request ID.

cc @Parthiv_Shah @JeremyChow

---

<div class="post-metadata">

**Author:** ![nkoynov](https://avatars.discourse-cdn.com/v4/letter/n/5f9b8f/32.png) [@nkoynov](https://forum.cursor.com/u/nkoynov)\
**Post date:** [October 21, 2026, 5:35am UTC](https://forum.cursor.com/t/cursor-sdk-local-agent-named-models-fail-with-status-error-and-no-error-message/164248/15 "2026-10-21T05:35:29Z")

</div>

No change on our side yet. In 1.0.40 a failed local run read back from the store still gets `{ message: errorCode }` with no `code`, both through `wait()` and when runs are listed, so it’s still empty here, as you said. I’ll retest when the version with the fix is out and post the request IDs if `code` is still empty.
