anomalyco / anomalyco/opencode
ACP: `opencode acp` fails to parse Content-Length framing on stdio — empty initialize response, agents see empty turns
@jlongster is already working on this.
Since Sep 13, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
What happened
opencode acp (stdio, Agent Client Protocol) fails to parse the very first JSON-RPC message (initialize) when it is framed with the standard Content-Length header used by ACP/LSP over stdio. The server logs a parse error to stderr and never answers; the client sees an empty stream / hang, and ACP clients end up with "empty agent turns".
Environment
- opencode:
1.18.29 - installed via: standalone binary at
/usr/bin/opencode(bun bundle) - OS: CachyOS (Arch-based), Linux 7.2.3
- terminal: not relevant (stdio transport)
Repro
Minimal Python script that speaks the framing ACP specifies (Content-Length: N\r\n\r\n + JSON):
import subprocess, json, threading
p = subprocess.Popen(
["opencode", "acp", "--cwd", "/tmp"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
def send(obj):
data = json.dumps(obj).encode()
p.stdin.write(f"Content-Length: {len(data)}\r\n\r\n".encode() + data)
p.stdin.flush()
send({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": 1,
"clientCapabilities": {
"fs": {"read_text_file": True, "write_text_file": True},
"terminal": True,
},
},
})
out = []
def reader():
while True:
b = p.stdout.read1(65536)
if not b:
break
out.append(b)
t = threading.Thread(target=reader, daemon=True)
t.start()
t.join(20)
print("BYTES RECEIVED:", sum(len(b) for b in out))
print("STDOUT RAW:", repr(b"".join(out)[:600]))
p.kill()
print("STDERR:", p.stderr.read().decode()[:800])
Actual result
BYTES RECEIVED: 0
STDOUT RAW: b''
STDERR: Failed to parse JSON message: Content-Length: 184 2 | // @bun
3 | `);o=ue.pop()||"";for(let We of ue){let N=We.trim();if(N)try{let E=JSON.parse(N);i.enqueue(E)}catch(E){console.error("Failed to parse JSON message:",N,E)}}}...
^
SyntaxError: JSON Parse error: Unexpected identifier "Content"
at start (/$bunfs/root/chunk-rat302vz.js:3:78)
Expected result
The server should consume the Content-Length: N\r\n\r\n framing header, parse the JSON body, and respond with a valid initialize result (protocolVersion + capabilities), then accept session/new / session/prompt normally.
Analysis
The error comes from the stdio JSON parser (bundled bun code): it appears to split the incoming buffer on newlines and JSON.parse each chunk, so the framing header line Content-Length: 184\r\n\r\n leaks into the parser as if it were JSON — hence Unexpected identifier "Content". When the body happens to be delivered in a way that survives this naive splitting, parsing sometimes succeeds; that matches the symptom we saw in production (via the opencode acp command run by an ACP client): sessions sometimes start and then return empty end_turn turns with zero tool calls, instead of failing loudly.
Context
This was diagnosed while running coding lanes through opencode acp on opencode 1.18.29: every lane returned end_turn with 0 chars and 0 tool calls in ~3-7s. The exact same model (opencode run --model <provider>/<model> "Responda exatamente: STATUS OK") answers correctly via the regular CLI, which rules out model/provider issues — the bug is in the ACP server's stdio framing parser.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.