{"record":{"id":"2715d7d48ff9726c","repo":"paperclipai/paperclip","slug":"createos-process-creation-could-not-be-confirmed-destroy-the","errorCode":null,"errorMessage":"CreateOS process creation could not be confirmed; destroy the lease before reusing it.","messagePattern":"CreateOS process creation could not be confirmed; destroy the lease before reusing it\\.","errorType":"exception","errorClass":"CreateosCleanupError","httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/execute.ts","lineNumber":197,"sourceCode":"          } 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.\n    try {\n      if (processId && !completed) {\n        try {\n          const termination = await client.json(`${base}/${processId}?grace_ms=1000`, \"DELETE\", undefined, cleanupSignal);\n          if (termination.tree_exited !== true) throw new Error(\"Process tree has not exited.\");","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/execute.ts#L179-L215","documentation":"CreateosCleanupError thrown when a failure occurs after the creation request was sent but before the server confirmed the processId. Because the process may actually have started, the provider cannot safely let the caller reuse the lease — a subsequent process could collide with an orphan. The lease must be destroyed before reuse.","triggerScenarios":"Any error (network failure, timeout, stream error) raised in execute() while creationMayHaveSucceeded is true and processId is still unset — i.e. the POST to create the process was sent, but the response with processId was never received.","commonSituations":"Connection dropped right after the create request; request timeout firing between send and response; server accepted the process but the response was lost.","solutions":["Destroy the sandbox lease before using it again — do not blindly retry commands on the same lease.","Check the lease/sandbox via the API for orphaned processes before re-provisioning.","Add retry logic at a higher level that creates a fresh lease instead of reusing this one.","Reduce timeoutMs churn: ensure client timeout is long enough for create round-trips."],"exampleFix":"// before\nawait execute(lease, cmd);\n// after\ntry {\n  await execute(lease, cmd);\n} catch (e) {\n  if (e instanceof CreateosCleanupError) await destroyLease(lease);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isCreateosCleanupError(e) {\n  return e instanceof CreateosCleanupError || e?.constructor?.name === \"CreateosCleanupError\";\n}","tryCatchPattern":"try {\n  await execute(lease, cmd, { signal });\n} catch (e) {\n  if (isCreateosCleanupError(e)) {\n    await destroyLease(lease); // mandatory: process state unconfirmed\n    throw e;\n  }\n  throw e;\n}","preventionTips":["Never reuse a lease after a CreateosCleanupError — always destroy it first.","Set client timeoutMs high enough for create round-trips to complete.","Wrap execute() in a helper that destroys the lease automatically on this error."],"tags":["sandbox","cleanup","lease","process"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}