{"record":{"id":"77ea2a4a4279ff59","repo":"Hmbown/CodeWhale","slug":"docker-exec-container-agent-returned-no-json-receipt","errorCode":null,"errorMessage":"docker exec ${container}: agent returned no JSON receipt","messagePattern":"docker exec (.+?): agent returned no JSON receipt","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/transport.mjs","lineNumber":262,"sourceCode":"  const remoteAgent = \"/app/docker/agent-exec.sh\";\n  const ex = {\n    kind: \"docker\",\n    container,\n    remoteAgent,\n    run(cmd, args = [], opts = {}) {\n      // Local side commands (docker itself) run directly.\n      return run(cmd, args, opts);\n    },\n    async remote(request, opts = {}) {\n      const r = await run(\"docker\", [\"exec\", container, \"/bin/sh\", remoteAgent, b64({ args: request.args ?? {}, tool: request.tool, nonce: crypto.randomBytes(6).toString(\"hex\") })], {\n        timeoutMs: opts.timeoutMs ?? 25_000,\n      });\n      if (r.aborted) throw Object.assign(new ExecError(\"computer request cancelled\", r), { code: \"cancelled\" });\n      if (r.timedOut) throw new ExecError(`docker exec ${container}: timed out`, r);\n      if (r.code !== 0) throw new ExecError(`docker exec ${container} exited ${r.code}: ${r.stderr.trim().slice(0, 400)}`, r);\n      const line = r.stdout.trim().split(\"\\n\").filter((l) => l.startsWith(\"{\")).pop();\n      const reply = line ? JSON.parse(line) : null;\n      if (!reply) throw new ExecError(`docker exec ${container}: agent returned no JSON receipt`, r);\n      return reply;\n    },\n  };\n  attachPersistentChannel(ex, binding, [\"docker\", \"exec\", \"-i\", container, \"/bin/sh\", remoteAgent, \"--serve\"]);\n  return ex;\n}\n\n/** Push the self-contained remote agent + src tree to an ssh computer. */\nexport async function installRemoteAgent(computer) {\n  const ex = sshExec(computer);\n  const srcDir = path.join(PLUGIN_ROOT, \"src\");\n  const rels = [\"agent.mjs\"];\n  for (const dir of [\"\", \"backends\"]) {\n    const full = path.join(srcDir, dir);\n    for (const f of fs.readdirSync(full)) {\n      if (f.endsWith(\".mjs\") || f.endsWith(\".m\") || f.endsWith(\".h\")) rels.push(`src/${dir ? dir + \"/\" : \"\"}${f}`);\n    }\n  }","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/transport.mjs#L244-L280","documentation":"After a successful (exit 0) `docker exec` run, the transport looks for the last stdout line starting with '{' as the agent's JSON reply and throws this ExecError if none exists. The agent must print exactly one JSON receipt line; this error means it printed none.","triggerScenarios":"executor.remote() on docker transport where the exec succeeds but stdout contains no '{'-prefixed line: agent missing/empty in the container, agent crashed after printing nothing, wrong file at the agent path, or stdout hijacked by wrapper scripts.","commonSituations":"Agent volume/upload missing in the container; entrypoint or shell rc echoes text but agent silently fails; stale container built without the agent; agent syntax unsupported by the container's node version.","solutions":["docker exec <container> /bin/sh <remoteAgent> with sample args to inspect raw output","Reinstall the agent into the container (re-run the docker agent install path)","Verify the agent file inside the container is non-empty and is the real agent.mjs","Check node availability/version in the container","Confirm nothing in the container's shell setup discards stdout"],"exampleFix":"// before\nawait ex.remote({ tool: \"platform\" }); // no JSON receipt\n// after\nconst chk = await run(\"docker\", [\"exec\", container, \"/bin/sh\", \"-c\", `wc -c ${remoteAgent}`]);\nif (chk.code !== 0 || chk.stdout.trim().startsWith(\"0\")) await installDockerAgent(ex, computer);\nawait ex.remote({ tool: \"platform\" });","handlingStrategy":"try-catch","validationCode":"const chk = await run(\"docker\", [\"exec\", container, \"/bin/sh\", \"-c\", `test -s ${remoteAgent} && echo ok`]);\nif (chk.code !== 0 || !chk.stdout.includes(\"ok\")) await installDockerAgent(computer);","typeGuard":"function isNoReceiptError(e) { return e instanceof ExecError && e.message.includes(\"no JSON receipt\"); }","tryCatchPattern":"try {\n  return await ex.remote(request, opts);\n} catch (e) {\n  if (e.message.includes(\"no JSON receipt\")) {\n    await installDockerAgent(computer); // reinstall, retry once\n    return ex.remote(request, opts);\n  }\n  throw e;\n}","preventionTips":["Re-copy agent files into the container after every agent update","Confirm the container's node can parse agent.mjs (syntax/version)","Check that entrypoint/shell wrappers do not swallow the agent's stdout"],"tags":["docker","json","remote-execution"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}