{"record":{"id":"1a4a9b2198e1b39a","repo":"paperclipai/paperclip","slug":"createos-process-stream-ended-without-an-exit-status","errorCode":null,"errorMessage":"CreateOS process stream ended without an exit status.","messagePattern":"CreateOS process stream ended without an exit status\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/execute.ts","lineNumber":192,"sourceCode":"              exitCode: typeof exitCode === \"number\" ? exitCode : null,\n              signal: typeof exitSignal === \"string\" ? exitSignal : null,\n              timedOut: false, stdout: output.stdout, stderr: output.stderr,\n              metadata: { processId, outputTruncated: output.truncated },\n            };\n          } else if (event.type === \"error\") {\n            throw new Error(event.error === \"output_offset_expired\"\n              ? \"CreateOS process output was evicted before it could be read.\"\n              : \"CreateOS process stream reported an error.\");\n          } else {\n            throw new Error(\"CreateOS returned an unknown process event.\");\n          }\n        }\n      } catch (error) {\n        // Network read failures can resume from the last accepted sequence.\n        // Protocol errors must fail closed rather than reconnect past bad data.\n        if (!(error instanceof TypeError) || signal.aborted) throw error;\n      }\n      if (++reconnects > 3) throw new Error(\"CreateOS process stream ended without an exit status.\");\n      await delay(250, undefined, { signal });\n    }\n  } catch (error) {\n    if (creationMayHaveSucceeded && !processId) {\n      throw new CreateosCleanupError(\"CreateOS process creation could not be confirmed; destroy the lease before reusing it.\");\n    }\n    if (signal.aborted && signal.reason?.name === \"TimeoutError\") {\n      output.finish();\n      return {\n        exitCode: null, timedOut: true, stdout: output.stdout, stderr: output.stderr,\n        metadata: { processId, outputTruncated: output.truncated },\n      };\n    }\n    if (signal.aborted) throw new Error(\"CreateOS command was cancelled.\");\n    throw error;\n  } finally {\n    const cleanupSignal = AbortSignal.timeout(client.config.timeoutMs);\n    // Do not hide a cleanup failure: the host must know containment is unproven.","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/execute.ts#L174-L210","documentation":"execute() reconnects to the process event stream on network read failures (TypeError) to resume from the last sequence number. If it exhausts more than 3 reconnect attempts without ever seeing an exit/terminal event, it concludes the stream ended without a status and throws this error. The caller cannot know the process exit code.","triggerScenarios":"More than 3 reconnect cycles (each preceded by a 250ms delay) end without the server delivering a terminal exit event — e.g. persistent network failure, the sandbox dying before emitting exit, or the stream closing cleanly but prematurely.","commonSituations":"Flaky network between host and sandbox; sandbox VM terminated by infra while process ran; CreateOS server restarting and dropping stream history; long-running process outliving stream retention.","solutions":["Re-run the command; the processId-based reconnect already retried 3 times.","Check sandbox lease health and recreate the lease if the sandbox is gone.","Increase network reliability or the reconnect budget if runs are long-lived over unstable links.","Query the process status out-of-band (GET /processes/:id) if the API offers it, to recover the exit code."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await execute(lease, cmd, { signal });\n} catch (e) {\n  if (e.message === \"CreateOS process stream ended without an exit status.\") {\n    // verify lease health, then retry once on a fresh lease\n    await ensureLeaseHealthy(lease);\n    return execute(freshLease(), cmd, { signal });\n  }\n  throw e;\n}","preventionTips":["Run long jobs over reliable links or with shorter checkpointable commands.","Recreate leases whose sandbox may have been recycled by infra.","Check process exit status out-of-band when the stream is unreliable."],"tags":["network","stream","reconnect","timeout"],"backgroundTag":"network-request-failed","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}