paperclipai/paperclip · error

Daytona sandbox is in an unrecoverable error state

Error message

Daytona sandbox ${sandbox.id} is in an unrecoverable error state: ${sandbox.errorReason ?? "unknown error"}

What it means

Lifecycle guard in ensureSandboxStarted: the Daytona sandbox object reports state 'error' (with sandbox.errorReason as detail, or 'unknown error' when absent), meaning the provider marked the sandbox unrecoverable. Every lease-holding hook (resume, realize, execute, sync, ingress, setup) routes through this check and aborts rather than attempting to start a dead sandbox.

Solutions

  1. Destroy and recreate the sandbox; inspect the reported errorReason in Daytona for root cause.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/plugins/sandbox-providers/daytona/src/plugin.ts:449 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-18). Data as JSON: /api/errors/768a5059e6660907. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugins/sandbox-providers/daytona/src/plugin.ts:467

  run: () => Promise<T>,
): Promise<T> {
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
    return run();
  }
  let timer: ReturnType<typeof setTimeout> | undefined;
  const deadline = new Promise<never>((_, reject) => {
    timer = setTimeout(() => reject(new SandboxLivenessTimeoutError(operation, timeoutMs)), timeoutMs);
  });
  try {
    return await Promise.race([run(), deadline]);
  } finally {
    if (timer !== undefined) clearTimeout(timer);
  }
}

async function ensureSandboxStarted(sandbox: Sandbox, timeoutSeconds: number): Promise<void> {
  if (sandbox.state === "started") return;
  // Bound the lifecycle call just past its own SDK deadline. A normal slow start
  // finishes within `timeoutSeconds`; only a connection-level hang the SDK
  // deadline misses reaches this wrapper bound.
  const startBoundMs = timeoutSeconds * 1_000 + LIVENESS_START_TIMEOUT_MARGIN_MS;
  if (sandbox.state === "error") {
    if (sandbox.recoverable) {
      await withLivenessTimeout("sandbox.recover", startBoundMs, () => sandbox.recover(timeoutSeconds));
      return;
    }
    throw new Error(`Daytona sandbox ${sandbox.id} is in an unrecoverable error state: ${sandbox.errorReason ?? "unknown error"}`);
  }
  await withLivenessTimeout("sandbox.start", startBoundMs, () => sandbox.start(timeoutSeconds));
}

async function resolveSandboxWorkingDirectory(sandbox: Sandbox): Promise<string> {
  const root = (await sandbox.getWorkDir())?.trim()
    || (await sandbox.getUserHomeDir())?.trim()
    || "/home/daytona";
  const remoteCwd = path.posix.join(root, "paperclip-workspace");

View on GitHub (pinned to 01ad858492)