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

  1. 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).
  2. Check which output stream produced the huge line (stdout/stderr) and reduce per-line verbosity, e.g. `tail`/`head`/filters before printing.
  3. Verify the CreateOS service version matches the frame protocol this plugin expects (newline-delimited JSON events with bounded size).
  4. If you control the server, raise the frame cap or ensure heartbeats/newlines flush output regularly.
  5. 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

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


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)