BYOK and sub-agents: Sub-agents fail with OpenAI models because optional Task arguments are sent as empty values

Where does the bug appear (feature/product)?

Bugbot / Security Review Agent

Describe the Bug

I troubleshooted the issue with Hermes using GPT-5.6 Sol (High) capturing and analyzing logs from my setting stored locally; here is the reply. Sorry for posting AI-slop, but I simply couldn’t log the failures, go through the logs, compare model performance issues, tool calls and compare them across different models myself.

The reply, formatted as readable as I can:

I use custom models in Cursor through an OpenAI-compatible custom model endpoint.

Sub-agents work correctly with one custom model through this same endpoint. Cursor accepts the Task tool call, launches the sub-agent, waits for it to finish, and returns its result to the parent agent.

With OpenAI-family models, however, the sub-agent never starts. The parent model retries the Task call three times and then the turn is canceled.

I captured and compared the complete request/response flow for a working custom model and a failing OpenAI model. The important difference is how the models populate optional arguments in Cursor’s Task tool.

The working custom model omits optional arguments it does not need:

json:
{
“description”: “Investigate frontend data sources”,
“prompt”: “…”,
“subagent_type”: “explore”
}

The OpenAI model sends almost every optional property with an empty or default value:

json:
{
“description”: “Trace frontend data sources”,
“prompt”: “…”,
“model”: “”,
“resume”: “”,
“readonly”: true,
“subagent_type”: “explore”,
“file_attachments”: ,
“environment”: “local”,
“cloud_base_branch”: “”,
“interrupt”: false,
“run_in_background”: false
}

Cursor rejects this combination:

json:
{
“environment”: “local”,
“cloud_base_branch”: “”
}

The error returned to the model is:

Error: Invalid arguments:
cloud_base_branch: cloud_base_branch may only be specified when environment equals cloud

Although cloud_base_branch is an empty string, Cursor treats it as specified. The Task schema says this property may only be specified when environment is “cloud”.

The parent OpenAI model receives the validation error but repeats the same invalid call three times. Cursor then cancels the final request. No sub-agent request is created.

Steps to Reproduce

  1. Configure an OpenAI-family model as a custom model in Cursor using an OpenAI-compatible custom model endpoint.

  2. Start a new agent conversation using that model.

  3. Ask the agent to delegate a repository investigation to a sub-agent. For example:
    text
    Use a sub-agent to investigate which data sources serve the different parts of this frontend. The sub-agent should be an Explore agent with medium thoroughness.

  4. Observe that the parent model produces a Task tool call containing:

json
{
“environment”: “local”,
“cloud_base_branch”: “”
}

  1. Cursor rejects the tool call with:
    cloud_base_branch: cloud_base_branch may only be specified when environment equals cloud

  2. The OpenAI model retries the same invalid call multiple times.

  3. No sub-agent is launched, and the parent turn eventually ends or is canceled.

For comparison, repeat the same prompt with another custom model through the same OpenAI-compatible endpoint. In my testing, that model emits only the required Task properties and subagent_type. Cursor accepts the call and launches the sub-agent normally.

Retry behavior

When Cursor returns a deterministic schema-validation error, the parent model currently retries the same arguments without changing them.

Cursor could either:

  1. normalize the arguments before the first validation; or
  2. return a machine-readable validation error that clearly instructs the model to omit the invalid property.

For example:

json
{
“error”: “invalid_task_arguments”,
“field”: “cloud_base_branch”,
“message”: “Omit cloud_base_branch when environment is local.”,
“retryable”: true
}

The most reliable fix is still normalization inside Cursor. It prevents the failure regardless of whether the model correctly responds to the validation error.

Expected Behavior

1. What the working custom model does

The successful custom model emits a minimal Task call:

json
{
“description”: “Investigate frontend data sources”,
“prompt”: “…”,
“subagent_type”: “explore”
}

It omits:

json
{
“model”: “”,
“resume”: “”,
“environment”: “”,
“cloud_base_branch”: “”,
“readonly”: “”
}

The Task schema only requires:
[“description”, “prompt”]

Cursor accepts the call and launches the child agent.

In the captured working run, the child agent then issued normal tool calls such as:

  • Read
  • Grep
  • Shell
  • UpdateCurrentStep

The child completed its investigation, and Cursor returned the completed Task result to the parent agent. This confirms that custom models can spawn sub-agents correctly through this endpoint.

2. What the OpenAI model does differently

The OpenAI model sends all optional properties, even when they have no meaningful value:

json
{
“model”: “”,
“resume”: “”,
“file_attachments”: ,
“environment”: “local”,
“cloud_base_branch”: “”,
“interrupt”: false,
“run_in_background”: false
}

The first deterministic failure is:

json
{
“environment”: “local”,
“cloud_base_branch”: “”
}

Cursor interprets the empty string as a supplied value and rejects the call.

The sequence from the captured run was:

  1. The OpenAI model returns a Task call.
  2. Cursor rejects it because cloud_base_branch is present while the environment is local.
  3. Cursor returns the validation error to the parent model.
  4. The model emits the same invalid Task call again.
  5. This happens three times.
  6. Cursor cancels the final parent request.
  7. No child-agent request is made.

The endpoint itself is not rejecting the request. The parent model requests complete successfully, and the Task tool call reaches Cursor. The failure happens during Cursor’s local validation or execution of the tool arguments.

3. Why this does not appear to be an endpoint issue

I compared the streamed Task arguments received from the model with the tool arguments returned to Cursor.

The arguments matched exactly. The custom endpoint did not add:
“cloud_base_branch”: “”

or any of the other empty/default fields.

The working model returned a minimal argument object, while the OpenAI model returned the expanded object with empty values. Both responses reached Cursor successfully.

The failing path is therefore:

Cursor parent request → custom model endpoint → OpenAI model returns a Task tool call → Cursor receives the complete Task call → Cursor rejects the Task arguments locally → no sub-agent is launched

The working comparison is:

text Cursor parent request → same custom model endpoint → another custom model returns a minimal Task call → Cursor accepts the Task call → sub-agent launches and completes → parent receives the Task result

4. The empty model property may be a second issue

The failing call also contains:
“model”: “”

Cursor’s schema describes model as optional:

“If omitted, the sub-agent uses the same model as the parent agent.”

An empty string is not the same as omitting the property. Cursor may later try to resolve “” as a model slug.

However, the captured run fails earlier on cloud_base_branch, so I cannot confirm from this trace whether model: “” causes a second validation or model-resolution failure.

The same applies to:
“resume”: “”

These empty optional strings should probably be normalized to omitted properties before Cursor validates or executes the tool call.

5. Root cause

The immediate cause is that the OpenAI model supplies:

{
“environment”: “local”,
“cloud_base_branch”: “”
}

Cursor treats cloud_base_branch as specified and rejects it because the environment is not “cloud”.

The broader issue is that OpenAI models appear to serialize optional Task properties using empty or default values rather than omitting them.

The working custom model follows the intended semantics of the schema and only emits properties it needs. The OpenAI model emits all available properties, including combinations that Cursor considers invalid.

6. Suggested fix

I think Cursor should normalize optional Task arguments before validating and executing them.

Recommended normalization

For optional string properties, Cursor could treat an empty string as omitted:

ts
function normalizeOptionalString(value: unknown): string | undefined {
if (typeof value !== “string”) {
return undefined;
}

const normalized = value.trim();
return normalized.length > 0 ? normalized : undefined;
}

Applied to a Task call:

ts
function normalizeTaskArguments(args: TaskArguments): TaskArguments {
const normalized = {
…args,
model: normalizeOptionalString(args.model),
resume: normalizeOptionalString(args.resume),
cloud_base_branch: normalizeOptionalString(args.cloud_base_branch),
};

if (normalized.environment !== “cloud”) {
delete normalized.cloud_base_branch;
}

if (normalized.model === undefined) {
delete normalized.model;
}

if (normalized.resume === undefined) {
delete normalized.resume;
}

return normalized;
}

The failing input:

json
{
“model”: “”,
“resume”: “”,
“readonly”: true,
“subagent_type”: “explore”,
“file_attachments”: ,
“environment”: “local”,
“cloud_base_branch”: “”,
“interrupt”: false,
“run_in_background”: false
}

would become:

json
{
“readonly”: true,
“subagent_type”: “explore”,
“file_attachments”: ,
“environment”: “local”,
“interrupt”: false,
“run_in_background”: false
}

Cursor could then validate and execute the normalized object.

Conditional handling for cloud_base_branch

Cursor should remove or ignore cloud_base_branch unless:

json
“environment”: “cloud”

This should apply even if the model sends:

json
“cloud_base_branch”: “”

An empty value has no operational meaning and should not make an otherwise local sub-agent request invalid.

Handling for model

Cursor should interpret:

json
“model”: “”

the same way as an omitted “model” property:
inherit the parent model or use the configured sub-agent model

This would also make the implementation more resilient to models that populate all optional schema properties.

Screenshots / Screen Recordings

Operating System

MacOS

Version Information

Version: 3.11.13 (Universal)
VS Code Extension API: 1.125.0
Commit: 3f21b08f0b436a07be29fbfe00b304fa15553350
Date: 2026-07-10T01:45:28.254Z
Layout: Agent Window
Build Type: Stable
Release Track: Nightly
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.256
OS: Darwin arm64 25.5.0

For AI issues: which model did you use?

I ran 3 tests to compare whether all models or only OpenAI models face this issue with BYOK. Result:

  1. BYOK, but the Cursor model selection of “GPT-5.6 Sol High”
  2. BYOK, but an OpenAI model, defined as a custom model (oai-5.6-terra(medium; screenshot attached)
  3. BYOK, but another custom, non-OpenAI model. Worked with sub-agents.

For AI issues: add Request ID with privacy disabled

Several IDs:
Other model, defined as a custom model, using the OpenAI URL BYOK: e549ff88-dbc8-4779-9505-0b979773c5b3
BYOK and OpenAI, using the defined Cursor model (GPT-5.6 Sol (High): 928e8c87-b59c-4c7b-be0a-2e261603fe79
BYOK and OpenAI, but defined as a custom model: 757dade0-6f14-42af-ada8-90a0b825cf87
Second try with BYOK and OpenAI: 03e52e8d-7ed6-412d-be51-7d92341d300c

Additional Information

I am already familiar with other threads, such as this, where:
a) the sub-agent always inherits the parent model (it seems) and the Cursor-native setting for sub-agents gets overwritten.
b) Composer-2.5 isn’t available as an option for sub-agents for a variety of reasons.

However, using BYOK and OpenAI models does not allow me to spawn any sub-agents whatsoever.

Additional diagnostic information

I have complete request/response logs for:

  • the working custom-model run;
  • the failing OpenAI-model run;
  • all three failed retries;
  • the successful child-agent execution from the working comparison;
  • the final successful Task result returned to the parent;
  • the final cancellation from the failing run.

I do not want to publish the raw logs because they contain local project and environment information. If Cursor staff wants to investigate, I would be happy to share a redacted capture privately or arrange a call and walk through the complete request sequence.

Does this stop you from using Cursor

Yes

Hi @user691!

Thanks for the investigation. I can’t reproduce this on my end – when using BYOK with OpenAI, subagents start as expected and only supply description and prompt to the Task tool.

Are you still encountering the issue?

Hi, thanks for your reply. Yes, the issue still occurs with BYOK and OpenAI models. In that case, I can be sure its a problem on my end and I just need to investigate it properly.

Actually just found an internal report of this one, so it’s on our radar. :folded_hands:

Oh, thanks a lot, I thought I was completely crazy/stupid. Other models I expose the same way can actually use sub-agents, but only inherit the parent model, not Cursors settings. If I were to use BYOK and Composer 2.5 for sub-agents, that would conflict (BYOK and Composer 2.5 doesn’t work).

However, using other models for sub-agents (configured through Cursor settings) and BYOK would be great. It’s a related issue (Sub-agents and BYOK), but I don’t want to post too much off-topic.

This should be fixed now (the empty cloud_base_branch issue), @user691. Can you check?

Hi Colin, thanks for your reply. I would have to run additional tests and logging to make sure this specific issue is resolved.
Current state:

  • I started a new chat with BYOK and another model (not-OpenAI) with sub-agents
  • I depleted the usage with that model
  • I switched to Sol-5.6 (high)
  • I was very positively surprised that it was able to use sub-agents regularly and continued with the OpenAI model

The request IDs in case that helps/youre interested:

  1. 3734f0ba-92f1-4457-b6be-95994eb0fa1e
  2. cbc5a2dc-45e3-415c-bb3c-d24853600af5

I haven’t tested it, but I am quite sure that with BYOK, the sub-agents still inherit the parent model. But that is a different issue. Thanks a lot to you and the Cursor team for looking into it!

I can confirm that when using BYOK, subagents always inherit the parent model.