{"record":{"id":"794dcc4c2b946078","repo":"paperclipai/paperclip","slug":"daytona-sandbox-handle-mismatch-handle-sandbox","errorCode":null,"errorMessage":"Daytona sandbox handle mismatch: handle ${sandbox.id} does not belong to lease ${providerLeaseId}.","messagePattern":"Daytona sandbox handle mismatch: handle (.+?) does not belong to lease (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/plugin.ts","lineNumber":1005,"sourceCode":"  const resolvedApiKey = config.apiKey ?? process.env.DAYTONA_API_KEY?.trim() ?? null;\n  return createHash(\"sha256\")\n    .update(stableStringify({\n      apiUrl: config.apiUrl,\n      // Target is a creation placement hint, not account identity: the SDK\n      // resolves existing sandboxes by ID. Lease metadata fills an omitted\n      // target with the actual region, which must not split admission state.\n      apiKey: resolvedApiKey,\n    }))\n    .digest(\"hex\");\n}\n\nfunction sandboxHandleCacheKey(scope: SandboxScope): string {\n  return stableStringify({\n    driverKey: scope.driverKey,\n    companyId: scope.companyId,\n    environmentId: scope.environmentId,\n    providerLeaseId: scope.providerLeaseId,\n    account: sandboxAccountDiscriminator(scope.config),\n  });\n}\n\nfunction assertHandleMatchesLease(sandbox: Sandbox, providerLeaseId: string): void {\n  // C2: a handle must never stand in for a different sandbox than the lease\n  // asked for. Belt-and-suspenders against a provider that returns a renamed or\n  // substituted sandbox, and against any future key collision.\n  if (sandbox.id !== providerLeaseId) {\n    throw new Error(\n      `Daytona sandbox handle mismatch: handle ${sandbox.id} does not belong to lease ${providerLeaseId}.`,\n    );\n  }\n}\n\n// A cached `Sandbox` carries the provider state captured when it was last\n// fetched/refreshed. Daytona auto-stops an idle sandbox after `autoStopInterval`\n// minutes, at which point that snapshot (\"started\") no longer matches reality\n// and `ensureSandboxStarted` would wrongly skip the restart, sending every","sourceCodeStart":987,"sourceCodeEnd":1023,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/daytona/src/plugin.ts#L987-L1023","documentation":"Belt-and-suspenders identity check (C2) in assertHandleMatchesLease: the sandbox handle the provider returned (sandbox.id) does not match the lease's providerLeaseId, suggesting a renamed or substituted sandbox. The driver refuses to use a handle that stands in for a different sandbox than the lease asked for, preventing cross-lease sandbox confusion.","triggerScenarios":"Thrown at packages/plugins/sandbox-providers/daytona/src/plugin.ts:956 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Use the sandbox handle that belongs to the lease; re-acquire the sandbox for the lease."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}