Repository navigation
Description
Description
When an ACP v2 agent accepts session/prompt and later reports an error through an idle state_update, T3 marks the turn as completed without showing the error.
This happened with acplause when OpenRouter rejected a request with HTTP 401. Fixing the API key restored normal responses, but T3 had hidden the authentication failure.
Environment
- T3 Code Beta 0.1.0, macOS
- ACP registry provider: acplause
- Negotiated protocol version: 2
- T3 source inspected: 9c16146
The relevant behavior was also confirmed in the installed app bundle.
Draft-version compatibility clarification
The two implementations use different ACP v2 draft revisions:
- acplause pins
2.0.0-alpha.9at upstream commit3be9cfc8ea2dfe5a28973b461fd956b4045f24d3: pinned version. - At the inspected T3 commit, the schema generator pins
schema-v2.0.0-alpha.3: generator source.
Both negotiate protocolVersion: 2, which does not distinguish these draft revisions. The newer contract reports failures after prompt insertion through an idle state update with stopReason: "error" and error details; T3's inspected idle schema has no error field.
This report therefore documents a compatibility gap when T3 interacts with an agent implementing the newer draft. The expected behavior and suggested tests below describe support for that newer contract. Maintainer triage should account for the draft-version mismatch when deciding whether to update the schema and handling or explicitly constrain supported revisions.
Steps to reproduce
- Configure acplause with an invalid OpenRouter API key.
- Open a session and select an available model.
- Send a prompt.
- Observe that T3 records the turn as completed without displaying the authentication error.
Protocol evidence
A separate diagnostic run of acplause using the same provider configuration accepted the prompt, then emitted this update:
{
"sessionUpdate": "state_update",
"state": "idle",
"stopReason": "error",
"error": {
"code": -32000,
"message": "Missing Authentication header",
"data": {
"kind": "auth",
"status": 401
}
}
}This is the params.update payload of a session/update notification. It is structured protocol data, not an error inferred from assistant text.
Expected behavior
The turn is marked failed and the agent's error message is displayed.
Actual behavior
The turn is marked completed and the error message is lost.
Relevant code
All links below refer to the inspected T3 commit:
- The generated idle state-update schema does not include
error. - The ACP client completion handler resolves prompt completion with
stopReason,usage, and_meta, omitting the idle error. - The provider adapter maps every resolved stop reason except
cancelledtocompleted.
Suggested regression coverage
A mock ACP v2 peer can accept the prompt and then emit the update above, without real credentials or API calls.
Assert that:
- The turn fails and retains the original error message.
stopReason: "error"without error details still fails with a fallback message.- Normal completion and cancellation retain their existing behavior.
- The turn is finalized exactly once.
This mock regression test has not yet been implemented.
Related reports
- [Bug]: Grok stop_reason "error" is normalized to end_turn — provider API errors are dropped and the turn is recorded as successful #8293 and merged PR fix(server): Grok API errors fail the run instead of completing it empty #14487 addressed a similar issue in Grok's provider-specific completion extension.
- [Bug]: Required MCP startup failure is recorded as a completed Antigravity ACP run #20097 was closed because no structured ACP failure was demonstrated. This report concerns an explicit ACP v2 idle error.
Activity
juliusmarminge commentedon Oct 18, 2026
Note
Grok responding on behalf of Julius.
Confirmed on main. This is a bug in our ACP v2 client, not an acplause extension.
The ACP v2 schema now defines
erroras a stop reason. An idlestate_updatewithstopReason: "error"can carry an optionalerrorfield holding a JSON-RPC error object (ErrorStopReason), and the spec says that after insertion thesession/promptresponse stays successful, so the idle update is the only place the failure shows up. Upstream added this in agentclientprotocol/agent-client-protocol#2281 and it shipped in schema 2.0.0-alpha.8. The payload in this report matches that shape.T3 still generates its v2 types from schema 2.0.0-alpha.3, which predates it:
packages/effect-acp/scripts/generate.tspinsschema-v2.0.0-alpha.3, and the idle variant inpackages/effect-acp/src/_generated/schema.gen.tshas onlystopReason,usageand_meta.packages/effect-acp/src/client.tsresolves the prompt completion with only those three fields, soerroris dropped.packages/provider-acp/src/server/adapter.tsmaps every stop reason other thancancelledtocompleted, so"error"finishes the turn as a success.#14487 fixed the same symptom only for Grok's own completion extension, so it doesn't cover generic ACP agents. #20097 was a different case with no structured failure.
Fixing it means understanding the newer stop reason and mapping
errorto a failed turn that keepserror.message, with a fallback message when no details are sent. The mock peer test outlined in the report covers the right cases.juliusmarminge commentedon Oct 22, 2026
Reproduced on current main b5a226e49c: Linux web dev client with an isolated server and acplause v0.202610.0, OpenAI GPT-4.1 Mini, deliberately invalid OpenRouter key. A fresh thread and a provider-handoff thread both persisted the ACP turn as completed without displaying the error. A separate acplause stdio run accepted the prompt and emitted the reported idle error with HTTP 401. Sanitized runtime transcript. This is a protocol/error-reporting bug; no exploitable vulnerability is reported.
juliusmarminge commentedon Oct 22, 2026
Fixed in #23218, mirrored as #23217. An accepted ACP v2 idle error now fails the turn and retains its message or a fallback. Existing command lifecycles remain unchanged. Focused registry and replay-fixture tests pass 31/31; two fresh reviews returned MERGE. Final proof audit. The PR is unmerged.
travelvector commentedon Oct 26, 2026
This symptom is also occurring with Kimi Code 2.3.1 on Windows x64, using the local ACP command
kimi acp, modelkimi-code/k3.1-pro, in T3 Code 0.1.3-nightly.20261026.3726 (version read from the running server).Although this issue is closed, #23218 is currently still open and unmerged. Could this issue remain open until the fix lands, and could the Kimi path be checked against it?
Observed behavior
An existing, previously working Kimi conversation encountered a TLS connection failure while refreshing OAuth credentials at
https://auth.kimi.com/api/oauth/token. The current turn stopped. Two subsequent user messages each finished after approximately 18 seconds with no assistant response and no visible error. T3 persisted both runs ascompleted.Correlated evidence
All timestamps below are UTC on 2026-10-26:
Kimi's own session
agents/main/wire.jsonlcontains:{"turnId":2,"outcome":"failed","errorMessage":"OAuthConnectionError: OAuth request to https://auth.kimi.com/api/oauth/token failed: fetch failed: Client network socket disconnected before secure TLS connection was established","type":"agent.turn.ended","time":1793052308148,"kind":"event"}It also records
turn.endedwithreason: "failed", an error namedOAuthConnectionError, andprompt.completedwithreason: "failed". The next prompt has the same failure at1793052353352.By contrast, T3's
t3_thread_readreportedstatus: "completed"for both runs. Their timeline contained the user messages and empty checkpoints, with no assistant message or failure item. The thread had no active run or pending request.These are Kimi's internal session events and T3's persisted run/timeline data; I did not capture the ACP stdio frames, so I cannot yet confirm that Kimi emits the exact idle
state_updatepayload shown in the original report. This is additional evidence of the same user-visible symptom, rather than proof of an identical protocol cause.Recovery and expected behavior
After connectivity recovered, a single constrained test in the same T3 thread and existing Kimi process successfully returned a short response at 22:10:23 UTC. No restart, re-login, or configuration change was needed.
T3 should expose the provider failure and mark the run failed, so the user can diagnose/retry it. A transient authentication-network failure should not appear as a successful empty response. Restoring connectivity resolved this occurrence, but did not address the missing error reporting.
No full conversation, credentials, or unrelated workspace contents are included here.
antonov256 commentedon Oct 29, 2026
Same symptom, different trigger: Kimi Code 2.3.3 via
kimi acp, T3 Code server 0.1.2 (linux x64), modelkimi-code/kimi-for-coding.In our case the provider hit its 5-hour usage limit. Outside ACP,
kimi -pprints the error clearly:Through
kimi acp, T3'ssession/promptreturns successfully in ~2-4 s, the turn is persisted ascompleted, and no turn items are produced (no reasoning, no assistant message) — the chat shows silence with no error. Reproduced on 3 consecutive prompts (01:45, 01:59, 02:38 UTC, 2026-10-29); the only earlier turn in the same session that did produce output was before the quota was exhausted.Server-side
statev2.sqliteconfirms the affected runs persisted onlyuser_message+checkpointitems with no provider items, and the ACP registry log shows eachsession/promptassucceeded.So this is a second trigger for the same failure class: plain API errors after prompt acceptance (429 usage limit), not only OAuth/TLS failures during credential refresh. Would be good if #23218 covers this path as well.
jamesdchen commentedon Nov 3, 2026
Still reproducing on T3 Code server 0.1.6 (linux x64) with Kimi Code 2.4.1 through
kimi acp, modelkimi-code/k3.1-pro. Same trigger as the 5-hour-limit report above. I saw it on about 10 threads in one evening, each started withdelegate_taskon a linked environment.What T3 shows
completed, about 4 seconds after the run starts.(The thread in the linked environment ended without a reply.)orchestrator_capabilitieskeeps reportingcanRunChildTask: truefor the provider, so the next delegate fails the same way.What the logs show for the same run
T3's provider event log has
session/promptgoing fromstartedtosucceededabout 3.9 s later, with a one-field result.Kimi's own session log (
~/.kimi-code/sessions/.../agents/main/wire.jsonl) has the real failure:So on this path the failure doesn't reach T3 as a
session/prompterror. I didn't capture the rawsession/promptresponse or itsstopReason, only the logged event, so I can't say which part of the fix in #23218 this path misses. It may be a stable-ACP path rather than the v2 idle-error one. #28658 looks like the same class on Antigravity.Why it matters for delegation: a coordinator can't tell "finished with nothing to say" from "never ran". I started six delegates that did nothing, then a further few, and only found the cause by reading Kimi's session log on the remote machine.
To reproduce: with a Kimi account at its 5-hour limit, start any Kimi thread or
delegate_task. Expected: a failed turn showing the provider's message, like the "Usage limit reached" state Claude and Codex threads get. I can share more of the redacted logs if useful.