paperclipai/paperclip · error
CreateOS process frame is too large.
Error message
CreateOS process frame is too large.
What it means
A newline-delimited JSON frame read from the CreateOS process output stream exceeded the 1 MiB MAX_LINE_BYTES limit. The plugin throws this to prevent unbounded memory growth when buffering stream lines; a frame this large is not a legitimate CreateOS event. It can be raised both for a completed line (line 45) and for an unterminated line still accumulating in `pending` (line 48).
Solutions
- Split large output inside the sandbox command before printing (chunk writes with newlines, or write to a file and read it via /files instead of stdout).
- Check which output stream produced the huge line (stdout/stderr) and reduce per-line verbosity, e.g. `tail`/`head`/filters before printing.
- Verify the CreateOS service version matches the frame protocol this plugin expects (newline-delimited JSON events with bounded size).
- If you control the server, raise the frame cap or ensure heartbeats/newlines flush output regularly.
- Catch the error and re-run the command with output redirected to a sandbox file, fetching it in bounded chunks afterward.
Example fix
// before ./dump-all --json | base64 -w0 # one gigantic line on stdout // after ./dump-all --json | base64 -w76 # wraps output across <1MiB lines
Defensive patterns
Strategy: validation
Validate before calling
// Estimate worst-case frame size before running
const approxBytes = Buffer.byteLength(command) + Number(params.env?.PAYLOAD_SIZE ?? 0);
if (approxBytes > 780_000) throw new Error("Expected single-line output exceeds the 1MiB CreateOS frame cap; use a file instead."); Type guard
function isWithinFrameCap(line: string): boolean { return line.length <= 1_048_576; } Try / catch
try { await execute(client, params, signal); }
catch (e) {
if (e instanceof Error && e.message.includes("frame is too large")) {
// re-run with output redirected to a sandbox file and chunked
} else throw e;
} Prevention
- Make sandbox commands emit newline-wrapped output (e.g. base64 -w76, fold -w).
- Avoid dumping large single-line blobs to stdout/stderr; use files plus the /files API.
- Keep expected output volume well under 1 MiB per line in command design.
- Pin and test against the CreateOS service version you deploy with.
When it happens
Trigger: The CreateOS sandbox /processes/:id/connect SSE-style stream emits a single JSON line longer than 1,048,576 characters — e.g. a `data` event whose data_base64 payload encodes more than ~780 KiB written to stdout/stderr between newlines, or a server sending one giant line without newline framing.
Common situations: A sandbox command dumps a huge single-line blob (base64 JSON, minified output) to stdout; a misbehaving or non-CreateOS server behind the connect endpoint sends garbage or oversized frames; a version change in the CreateOS service batches output differently, removing newline boundaries.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- github_attachment_canonical_api_too_large
- OpenCode SSE event exceeded the retained payload limit
- A sandbox command is required.
- [adapter-ui-loader] Failed to load UI parser for
- AgentMail response exceeds the processing limit
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/fdcd3ebf6e88046c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/execute.ts:45
params.cwd ? `cd -- ${shellQuote(params.cwd)} || exit` : "",
`exec env ${env.join(" ")} ${command}${stdinPath ? ` < ${shellQuote(stdinPath)}` : ""}`,
].filter(Boolean).join("\n");
}
async function* events(response: Response): AsyncGenerator<Record<string, unknown>> {
if (!response.body) throw new Error("CreateOS returned an empty process stream.");
const reader = response.body.getReader();
const decoder = new TextDecoder();
let pending = "";
try {
for (;;) {
const { value, done } = await reader.read();
pending += done ? decoder.decode() : decoder.decode(value, { stream: true });
let newline: number;
while ((newline = pending.indexOf("\n")) >= 0) {
const line = pending.slice(0, newline);
pending = pending.slice(newline + 1);
if (line.length > MAX_LINE_BYTES) throw new Error("CreateOS process frame is too large.");
if (line.trim()) yield parseEvent(line);
}
if (pending.length > MAX_LINE_BYTES) throw new Error("CreateOS process frame is too large.");
if (done) {
if (pending.trim()) yield parseEvent(pending);
return;
}
}
} finally {
await reader.cancel().catch(() => undefined);
reader.releaseLock();
}
}
function parseEvent(line: string): Record<string, unknown> {
try { return object(JSON.parse(line)); }
catch { throw new Error("CreateOS returned an invalid process frame."); }
}View on GitHub (pinned to 3f1d897a7c)