paperclipai/paperclip · error
Bridge response envelope changed while reading.
Error message
Bridge response envelope changed while reading.
What it means
The response file can change between the stat and the read loop (the host is still writing, or another process replaced it). After reading, if the bytes read do not equal the originally statted size, the bridge assumes the envelope is inconsistent and refuses to parse it, since a partial or rewritten JSON envelope would be corrupt.
Solutions
- Retry the bridge request; the stale file is removed and a fresh response is written.
- Ensure only one host process serves the shared bridge directory.
- Fix the host to write responses atomically (write to temp file, rename into place).
- Verify no crash/interruption truncated the host's write; check host logs.
Defensive patterns
Strategy: retry
Try / catch
try { return await waitForResponse(id); } catch (e) {
if (e.message.includes("changed while reading")) { await sleep(pollIntervalMs); return waitForResponse(id); }
throw e;
} Prevention
- Run exactly one host process per shared bridge directory
- Have the host write responses atomically (temp file + rename)
- Retry once on this error before surfacing a failure
- Check host logs for crashes during response writes
When it happens
Trigger: In waitForResponse, the read loop accumulates length !== stat.size for the response file at <responsesDir>/<requestId>.json.
Common situations: Host still mid-write when the sandbox opens the file (write-then-rename not used); two hosts sharing one responses directory; filesystem where append partially completed (crash during write).
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Bridge envelope changed while reading.
- Bridge envelope exceeded the configured size limit.
- Bridge envelope too large
- Bridge response envelope exceeded the configured size limit.
- CreateOS lease cleanup is already in progress.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/286661aa8e7f1c3c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/adapter-utils/src/sandbox-callback-bridge.ts:2428
const deadline = Date.now() + responseTimeoutMs;
while (Date.now() < deadline) {
const handle = await fs.open(responsePath, "r").catch(error => {
if (error.code === "ENOENT") return null;
throw error;
});
if (handle) {
try {
const stat = await handle.stat();
if (stat.size > sandboxBridgeEnvelopeLimit(maxBodyBytes)) throw new Error("Bridge response envelope exceeded the configured size limit.");
reserveResponse(6 * stat.size + 1);
const bytes = Buffer.alloc(stat.size + 1);
let length = 0;
while (length < bytes.length) {
const read = await handle.read(bytes, length, bytes.length - length, length);
if (!read.bytesRead) break;
length += read.bytesRead;
}
if (length !== stat.size) throw new Error("Bridge response envelope changed while reading.");
return JSON.parse(bytes.subarray(0, length).toString("utf8"));
} finally {
await handle.close();
await fs.rm(responsePath, { force: true }).catch(() => undefined);
}
}
await sleep(pollIntervalMs);
}
throw new Error("Timed out waiting for host bridge response.");
}
const server = createServer(async (req, res) => {
// readBodyBytes reserves the body's bytes against the process ledger and
// hands back a release function; this holds it so the finally below
// releases those bytes exactly once no matter how this handler ends —
// its normal completion, a thrown error, a client abort, or a deadline
// timeout all reach the same finally.
let releaseBodyReservation = null;View on GitHub (pinned to 3f1d897a7c)