Skip to content

Commit 8614b96

Browse files
aorumbayevclaude
andcommitted
fix: skip blank/whitespace-only lines in receive loop
`_receive_loop` only checked for EOF (`b""`), but blank lines like `b"\n"`, `b" \n"`, or `b"\r\n"` are truthy and fell through to `json.loads()`, causing `JSONDecodeError: Expecting value: line 1 column 2 (char 1)`. This is common on WSL where Windows-native agent subprocesses emit `\r\n` blanks, or any CLI that prints empty lines to stdout alongside JSON-RPC frames. Strip each line and skip it when empty before attempting JSON parse. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0133bc4 commit 8614b96

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

src/acp/connection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ async def _receive_loop(self) -> None:
151151
line = await self._reader.readline()
152152
if not line:
153153
break
154+
line = line.strip()
155+
if not line:
156+
continue
154157
try:
155158
message: dict[str, Any] = json.loads(line)
156159
except Exception:

tests/test_rpc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,24 @@ async def test_ignore_invalid_messages(connect, server):
282282
await asyncio.wait_for(server.client_reader.readline(), timeout=0.1)
283283

284284

285+
@pytest.mark.asyncio
286+
async def test_blank_lines_skipped_without_error(connect, server):
287+
"""Blank/whitespace-only lines on the wire must not cause JSONDecodeError."""
288+
connect(connect_agent=True, connect_client=False)
289+
290+
# Send blank lines, then a valid request
291+
for noise in [b"\n", b" \n", b"\r\n"]:
292+
server.client_writer.write(noise)
293+
req = {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": 1}}
294+
server.client_writer.write((json.dumps(req) + "\n").encode())
295+
await server.client_writer.drain()
296+
297+
line = await asyncio.wait_for(server.client_reader.readline(), timeout=1)
298+
resp = json.loads(line)
299+
assert resp["id"] == 1
300+
assert "result" in resp
301+
302+
285303
class _ExampleAgent(Agent):
286304
__test__ = False
287305

0 commit comments

Comments
 (0)