paperclipai/paperclip · error · CreateosCleanupError

CreateOS command cleanup failed; process termination is…

Error message

CreateOS command cleanup failed; process termination is unconfirmed.

What it means

CreateosCleanupError thrown when post-run process termination fails for any reason other than a 404 (process already gone). The host must know that containment is unproven — the process may still be running in the sandbox. The 404 case is tolerated because a missing process means it already exited.

Solutions

  1. Destroy the lease entirely — treat it as poisoned, since termination is unconfirmed.
  2. Increase client.config.timeoutMs if cleanup routinely exceeds the timeout.
  3. Retry termination once before destroying the lease.
  4. Check sandbox/lease status via API to confirm whether the process survived.

Example fix

// before
catch (error) { if (!(error instanceof CreateosApiError && error.status === 404)) throw new CreateosCleanupError("..."); }
// after
catch (error) {
  if (error instanceof CreateosApiError && error.status === 404) break; // already gone
  await destroyLease(lease); // fail safe: reclaim the whole sandbox
  throw new CreateosCleanupError("...");
}
Defensive patterns

Strategy: try-catch

Type guard

function isCreateosCleanupError(e) {
  return e instanceof CreateosCleanupError;
}

Try / catch

try {
  return await execute(lease, cmd, { signal });
} catch (e) {
  if (isCreateosCleanupError(e)) {
    await destroyLease(lease); // treat lease as poisoned
  }
  throw e;
}

Prevention

When it happens

Trigger: DELETE /sandboxes/:id/processes/:pid fails with a network error, non-404 HTTP status, times out (cleanupSignal), or the inner 'Process tree has not exited.' error is raised — anything except CreateosApiError with status 404.

Common situations: Sandbox became unreachable after the run; cleanup AbortSignal.timeout(client.config.timeoutMs) fired during a slow termination; server returned 500 during termination; permission/lease state changed mid-cleanup.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/4f3ae50849c7ee56. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugins/sandbox-providers/createos/src/execute.ts:217

    if (signal.aborted && signal.reason?.name === "TimeoutError") {
      output.finish();
      return {
        exitCode: null, timedOut: true, stdout: output.stdout, stderr: output.stderr,
        metadata: { processId, outputTruncated: output.truncated },
      };
    }
    if (signal.aborted) throw new Error("CreateOS command was cancelled.");
    throw error;
  } finally {
    const cleanupSignal = AbortSignal.timeout(client.config.timeoutMs);
    // Do not hide a cleanup failure: the host must know containment is unproven.
    try {
      if (processId && !completed) {
        try {
          const termination = await client.json(`${base}/${processId}?grace_ms=1000`, "DELETE", undefined, cleanupSignal);
          if (termination.tree_exited !== true) throw new Error("Process tree has not exited.");
        }
        catch (error) { if (!(error instanceof CreateosApiError && error.status === 404)) throw new CreateosCleanupError("CreateOS command cleanup failed; process termination is unconfirmed."); }
      }
    } finally {
      if (staged && stdinPath) {
        // /files has no delete verb. /exec supplies a bounded, one-shot removal
        // after the managed process finishes, without retaining another record.
        await client.json(`/sandboxes/${id}/exec`, "POST", {
          cmd: "/bin/rm", args: ["-f", "--", stdinPath],
        }, cleanupSignal).catch(() => undefined);
      }
    }
  }
}

View on GitHub (pinned to 3f1d897a7c)