{"record":{"id":"c8011ab0324a7440","repo":"paperclipai/paperclip","slug":"daytona-sandbox-not-found","errorCode":"daytona_sandbox_not_found","errorMessage":"daytona_sandbox_not_found","messagePattern":"daytona_sandbox_not_found","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/plugin.ts","lineNumber":2865,"sourceCode":"    try {\n      return await withSandboxActivityGate(scope, async () => {\n        const sandbox = await getSandbox(scope, { bypassTeardownGate: true });\n        await ensureSandboxStarted(sandbox, timeoutSeconds);\n        const result = await performSyncOut({\n          sandbox,\n          operations: params.operations,\n          remoteDir,\n          timeoutSeconds,\n        });\n        sandboxHandleCache.markFresh(scope);\n        return result;\n      });\n    } catch (error) {\n      // A deleted Daytona sandbox is the one provider failure that proves its\n      // unexported workspace bytes no longer exist. Convert the SDK class to a\n      // stable cross-worker message; every other error remains retryable.\n      if (error instanceof DaytonaNotFoundError) {\n        throw new Error(\"daytona_sandbox_not_found\");\n      }\n      throw error;\n    }\n  },\n\n  // Open one live login pseudo-terminal. Resolve the cached sandbox by the\n  // provider lease id, revalidate the host launch descriptor, create the session\n  // home with one `mkdir -p` command, run the fixed login command on a real\n  // pseudo-terminal, and register the session under the host route id. Stream the\n  // raw output and the exit through `ctx.loginPty`, bound to the returned worker\n  // session id. Fail closed when no cached sandbox matches the lease.\n  async onLoginPtyOpen(params) {\n    const sandbox = await sandboxHandleCache.findByProviderLeaseId(params.providerLeaseId);\n    if (!sandbox) {\n      throw new Error(\n        \"Daytona login pseudo-terminal: no cached sandbox resolves the provider lease.\",\n      );\n    }","sourceCodeStart":2847,"sourceCodeEnd":2883,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/plugins/sandbox-providers/daytona/src/plugin.ts#L2847-L2883","documentation":"When a Daytona sandbox provider operation fails because the sandbox no longer exists, the plugin catches DaytonaNotFoundError from the SDK and rethrows a plain Error with the stable message 'daytona_sandbox_not_found'. The comment explains that a deleted sandbox is the one provider failure proving the unexported workspace bytes are gone; converting the SDK class to a stable cross-worker message lets other workers treat it as non-retryable, while all other errors remain retryable.","triggerScenarios":"Any Daytona SDK call inside the plugin (stop/exec, snapshot, or workspace ops around plugin.ts:2865) rejects with DaytonaNotFoundError because the sandbox was deleted (expired TTL, manual deletion in Daytona dashboard, account/region issue, or garbage collection).","commonSituations":"Sandbox auto-expired after idle timeout while a worker still held a cached reference; operator deleted sandboxes to free quota; Daytona cleaned up stale sandboxes; multi-worker setups where another worker already exported and removed the workspace.","solutions":["Treat the message 'daytona_sandbox_not_found' as terminal: stop retrying and recreate the sandbox/workspace from source instead of the deleted instance","Export/snapshot workspace bytes before deletion so the work is recoverable after a not-found error","Check the Daytona console/API for the sandbox ID to confirm deletion and whether a snapshot exists to restore from","Align sandbox TTL/keep-alive settings with workload duration so long jobs are not orphaned","Clear the cached sandbox reference in the plugin state and provision a fresh sandbox for the task"],"exampleFix":"// before (retry loop on all errors)\ncatch (e) { await retry(op); }\n// after\ntry { await op(); } catch (e) {\n  if (e.message === 'daytona_sandbox_not_found') return recreateSandboxAndRerun(); // terminal, do not retry\n  await retry(op);\n}","handlingStrategy":"fallback","validationCode":"const exists = await daytonaClient.sandbox.get(sandboxId).then(() => true, e => !(e instanceof DaytonaNotFoundError)); if (!exists) provisionNewSandbox();","typeGuard":"function isSandboxNotFound(e: unknown) { return e instanceof Error && e.message === 'daytona_sandbox_not_found'; }","tryCatchPattern":"try { await sandboxOp(); } catch (e) { if (isSandboxNotFound(e)) { return recreateSandboxFromSnapshot(); } throw e; // other errors remain retryable }","preventionTips":["Export/snapshot workspace bytes before sandbox deletion or TTL expiry","Match sandbox keep-alive/TTL settings to expected workload duration","Clear cached sandbox references after a not-found error and provision fresh","Monitor Daytona deletions and alert before sandboxes used by active tasks disappear"],"tags":["sandbox","daytona","not-found","non-retryable","cloud"],"backgroundTag":"resource-not-found","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}