Repository navigation
tool calls: arguments corrupt across calls and schema-invalid calls can execute #47902
Description
Summary
During one OpenCode V2 session, tool arguments became corrupted across multiple consecutive assistant turns. A patch argument literally ended with internal-looking serialization markers (<|DELIM_AE|>step_type...); other calls were truncated, contained injected words, mixed fields from another tool schema, or produced malformed paths. A later corrupted read call requested permission for an unrelated path under C:\Users\Harry\....
Patch validation rejected the malformed patch requests. The user declined the unexpected read permission; the durable tool record says executed: false and The user declined this tool call. The incident was alarming because corrupted path fragments then also appeared in ordinary assistant text.
Environment
- opencode version:
opencode2 v0.0.0-beta-19296 - OS:
Microsoft Windows [Version 10.0.26200.9168](win32 x64) - Terminal: Windows Terminal (
WT_SESSIONset);TERM=xterm-256color;TERM_PROGRAMandCOLORTERMunset - Shell:
C:\WINDOWS\system32\cmd.exe(ComSpec); tool processes were spawned with PowerShell 7 - Install/channel: installed V2 beta (
local=falsein CLI log). A separate legacyopencode 1.18.16executable is also on PATH but was not the client in use. - Active plugins: none configured in the effective
/api/config; no local plugin files found in the workspace or global OpenCode config plugin directories - Provider/model: native
openai/gpt-5.6-sol, varianthigh - Shared service after the incident: healthy on the same beta version; service run ID associated with the parent activity was
6fed79f9
Reproduction
The failure was repeated many times within one session but has not been reproduced deterministically in a fresh session.
- Use a long OpenCode V2 session with
openai/gpt-5.6-sol(high) on Windows. - Ask the assistant to make a sequence of repository edits using the
patchtool. - Observe consecutive tool calls around
2026-09-08T06:13Z–06:23Z. - Inspect persisted session messages/tool state. Some patch calls are valid, while others have truncated or corrupted arguments despite the assistant messages finishing with
finish: "tool-calls". - Continue the conversation. In this incident, corruption progressed from patch text/path arguments to an unrelated
readpath and then malformed path fragments in ordinary assistant text.
Captured session: ses_f99489a00ffest1oZ62oS41GuV.
Expected Behavior
Tool arguments should contain only the model's intended, schema-valid payload. Internal serialization markers must never appear in tool input. Fields must not migrate between tool schemas, and malformed generated paths must not trigger unrelated external-filesystem permission prompts.
If provider output is corrupted, OpenCode should classify and stop/retry it before presenting a filesystem permission request, while preserving enough safe diagnostics to identify whether corruption occurred at the provider stream, adapter, or message-serialization boundary.
Actual Behavior
At 2026-09-08T06:17:09.471Z, a persisted patchText ended exactly as follows (project content before the marker redacted):
[redacted patch content]<|DELIM_AE|>step_type<|DELIM_AE|>step_content<|DELIM_AE|>content_hash<|DELIM_AE|>provenance
<|DELIM_AE|>
The patch validator rejected it because the last line was not *** End Patch. Durable IDs:
message: msg_07fa9ab76001IDBvD254anx86P
part: call_LeagPElcnVkyxYkwwZJchbl1
provider item: fc_0f4c75c33f7cbbf4016a9fa867311087d2b94a22ff1785a53a
Another corrupted patch call had input fields from both patch and grep:
{
"fields": ["patchText", "path", "include", "caseSensitive", "limit"],
"patchTextEndedWithEndPatch": false
}Its error was:
patch verification failed: The last line of the patch must be '*** End Patch'
Other exact validation/runtime symptoms in the same cluster included:
Invalid hunk at line 38: Update file hunk for path 'C:\_{' is empty
Update file hunk for path 'book-pencil55? no' is empty
Working directory does not exist: C:\Users\[user]\opencode\ Eich
Failed to read file to update C:\Users\[user]\opencode\book-power outdoors: file does not exist
Invalid arguments for tool "shell": command: Missing key
Arguments provided: { "path": "C:\Users\[user]\opencode\bookHeld?", "offset": 1, "limit": 2 }
Patch content also acquired unrelated suffixes such as Nancy?, stereotrippinovoices??, and feder249.
Across the roughly ten-minute cluster, persisted tool state contains:
- 37 patch calls: 14 completed and 23 rejected
- 15 of the 23 rejected patches were missing the required final
*** End Patch - 8 had other malformed hunks, injected text, or malformed paths
- 2 malformed shell calls
- 1 unexpected read call
At 2026-09-08T06:22:43.564Z, the assistant emitted this read input:
C:\Users\Harry\oplish\FOP?lify?Invalid path? no.
Durable state:
message: msg_07faec16e0015T8TAQGX7uNCzk
part: call_w2j92ZXzxvfyMDWZZViZBDIP
tool: read
status: error
executed: false
error: The user declined this tool call
The assistant subsequently emitted malformed path fragments in normal text, including C:\ibele\Users\Harry\... and C:\Users\[user]\abatement\opSED? Wait—this....
Additional Context
- This appears related to fix(llm): handle truncated OpenAI tool arguments #36766, but is materially different from a tool argument merely ending mid-JSON. Here the tool object parsed and reached validation, while its string content contained internal-looking delimiter names; other calls mixed schema fields or inserted unrelated words and paths.
- No query for
DELIM_AE,"step_type" "step_content", tool-payload corruption, or malformed/truncated tool arguments found an issue covering this exact delimiter leak plus cross-call corruption. - No
WARNorERRORlines matched the parent session/run in the normal OpenCode log during the incident window. The delimiter was found in the persisted session message/tool input, not the log. - The parent session was long (about 182k–192k cached-input tokens around the incident), but the affected messages had ordinary nonzero output token counts and
finish: "tool-calls"; there was no recordedfinish: "length"on the cited calls. - Valid patch calls in the same cluster did execute. Existing user edits were intentionally left untouched; this report does not claim every call was corrupt.
- Cause is not established. The evidence is consistent with provider/adapter/message-serialization corruption, but does not by itself identify which boundary introduced it.
- No service restart, destructive database operation, or fresh dependency/build action was performed during diagnosis.
Activity
opencode-agent commentedon Sep 8, 2026
Could you attach the sanitized OpenCode logs covering the incident window (
2026-09-08T06:13Z–06:23Z), including all lines for the relevant serverrunID rather than onlyWARN/ERRORlines? The installed-build log is at~/.local/share/opencode/log/opencode.log(on Windows, under your user profile). Please redact API keys, authorization headers, prompts, file contents, and other sensitive data before uploading.If you have a session export for
ses_f99489a00ffest1oZ62oS41GuV, please attach that too after the same redaction.zhiganov commentedon Sep 8, 2026
Thanks — I prepared and reviewed both requested artifacts. They are ready to attach below:
opencode-2026-09-08T0613Z-0623Z-run-6fed79f9-sanitized.logsession-sanitized.jsonSanitization and integrity notes:
6fed79f9and falls within2026-09-08T06:13Z–06:23Z; process arguments, working directories, and executable paths are redacted.opencode2 export --sanitize ses_f99489a00ffest1oZ62oS41GuV, then passed through a second sanitizer because 73 nested tool-error messages still contained paths, project names, command arguments, or expected-content excerpts.Additional occurrences after the original report:
2026-09-08T12:23:50.518Z, the durable export records ashelltool error (msg_080f96d60001BjDLpDzSX5NzLa,call_gRVqqgUyio75Gq92e9IZAHcJ) after its workdir was corrupted toC:\Users\[user]\opencode\beautifulbots? No.. The public export retains the IDs, timestamp, tool, and error status while replacing the path-bearing error message with a categorical placeholder.These artifacts do not establish malware or identify whether the provider, adapter, or message-serialization boundary introduced the corruption.
SHA-256:
52F222C8E268B0CF6A3B059E79AFCE50DA60482D6015E9FE03CFC492F0EAFFAC780B33E374607851017F82CDE9CDA7B60016D3A5C24C67B29470C79361095762opencode-2026-09-08T0613Z-0623Z-run-6fed79f9-sanitized.log
session-sanitized.json
zhiganov commentedon Sep 9, 2026
A second occurrence on
v0.0.0-beta-19378adds one material finding:OpenCode accepted and executed parseable tool calls that contained a valid required argument plus unknown JSON properties. Four affected shell calls completed with exit code 0. One performed an external GitHub mutation; the resulting corrupt text was subsequently repaired.
The persisted tool state contains the unknown properties before execution, and the process-spawn log shows the corresponding already-corrupted PowerShell command. This strengthens the need for strict argument validation: unknown properties should reject the entire call rather than allowing the valid portion to execute.
No private repository names, project content, credentials, or raw command bodies are included here.
[-]llm: tool arguments leak DELIM_AE markers and corrupt across calls[/-][+]tool calls: arguments corrupt across calls and schema-invalid calls can execute[/+]DovydasNavickas commentedon Sep 12, 2026
Got very similar situations in multiple projects while using opencode2 in all of them with
GPT-5.6 High, e.g.:cd ~/Projects/myproject CH? Wait path. Must exact. && rtk git diff --cached --unified=20 -- state/main.ymlIn another one:
rtk git show a0aed8d2^:projects/Bookkeepingтобыchito pits? no.Those are Cyrillic characters right after the path excerpt 🙊 Could this be coming from some sort of prompt injection? Or is it just Sol generating random stuff?
P.S. This is happening on Linux, so this is not Windows specific.
chenhz01 commentedon Sep 17, 2026
The delimiter leak (
<|DELIM_AE|>) plus cross-schema field migration is a nasty capture, and the durable tool records make this report unusually strong — havingexecuted: falseon the dangerousreadcall is exactly the kind of evidence this class of bug usually lacks.From our side: we enforce schema validation before execution on every tool call, and two invariants caught our own corruption class early:
patchTextalongsideinclude/caseSensitive/limit) fails this immediately and loudly.Agree with the report's framing: classify-and-stop at the provider/adapter/message-serialization boundary beats letting corrupted arguments reach permission gating — a declined permission is a near-miss, not a defense.