{"record":{"id":"679db4c073b9a744","repo":"paperclipai/paperclip","slug":"createos-returned-an-invalid-process-frame","errorCode":null,"errorMessage":"CreateOS returned an invalid process frame.","messagePattern":"CreateOS returned an invalid process frame\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/execute.ts","lineNumber":62,"sourceCode":"        pending = pending.slice(newline + 1);\n        if (line.length > MAX_LINE_BYTES) throw new Error(\"CreateOS process frame is too large.\");\n        if (line.trim()) yield parseEvent(line);\n      }\n      if (pending.length > MAX_LINE_BYTES) throw new Error(\"CreateOS process frame is too large.\");\n      if (done) {\n        if (pending.trim()) yield parseEvent(pending);\n        return;\n      }\n    }\n  } finally {\n    await reader.cancel().catch(() => undefined);\n    reader.releaseLock();\n  }\n}\n\nfunction parseEvent(line: string): Record<string, unknown> {\n  try { return object(JSON.parse(line)); }\n  catch { throw new Error(\"CreateOS returned an invalid process frame.\"); }\n}\n\nclass Output {\n  stdout = \"\";\n  stderr = \"\";\n  truncated = false;\n  private decoders = { stdout: new StringDecoder(\"utf8\"), stderr: new StringDecoder(\"utf8\") };\n  constructor(private log: (stream: \"stdout\" | \"stderr\", text: string) => void) {}\n\n  private append(stream: \"stdout\" | \"stderr\", text: string) {\n    if (!text) return;\n    this.log(stream, text);\n    const combined = this[stream] + text;\n    if (combined.length > MAX_CAPTURE_CHARS) this.truncated = true;\n    this[stream] = combined.slice(-MAX_CAPTURE_CHARS);\n  }\n\n  write(stream: \"stdout\" | \"stderr\", bytes: Buffer) {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/execute.ts#L44-L80","documentation":"A non-empty line from the CreateOS process stream failed JSON.parse or did not produce an object (via the `object()` helper). The plugin expects every frame to be a JSON object event (heartbeat/data/exit/error); anything else is treated as a protocol violation and fails closed rather than being reconnected past.","triggerScenarios":"The /processes/:id/connect stream emits a line that is invalid JSON (truncated frame, HTML error page, plain-text message), or valid JSON that is not an object (array, string, number).","commonSituations":"A proxy/load balancer injects an HTML 502 page into the stream; the sandbox command echoes non-JSON directly into the event channel due to a server-side framing bug; a CreateOS protocol version change renames or restructures event payloads.","solutions":["Log/capture the offending line and compare it against the expected event schema (type: heartbeat|data|exit|error).","Check for proxies or gateways between the plugin and CreateOS that could inject non-JSON bodies into the stream.","Verify CreateOS service version compatibility; protocol changes can break frame parsing.","Retry the command; if persistent, inspect the sandbox's process endpoint directly with curl to see the raw frames."],"exampleFix":"// before\nconst ev = JSON.parse(line);          // throws raw SyntaxError on bad frames\n// after (plugin behavior)\ntry { const ev = object(JSON.parse(line)); } catch { /* invalid process frame */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await execute(client, params, signal); }\ncatch (e) {\n  if (e instanceof Error && e.message === \"CreateOS returned an invalid process frame.\") {\n    log.error(\"Non-JSON frame from CreateOS; check proxies and service version\");\n    // retry once, then fail with diagnostics\n  } else throw e;\n}","preventionTips":["Bypass or audit proxies between the plugin and CreateOS that could inject HTML error pages.","Keep the CreateOS service version aligned with the plugin protocol.","Alert on this error: repeated occurrences mean server-side corruption, not transient faults.","Capture raw stream frames during incidents for upstream bug reports."],"tags":["json","protocol","streaming"],"backgroundTag":"invalid-json-response","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}