{"record":{"id":"389baf2bdc9a1797","repo":"paperclipai/paperclip","slug":"daytona-sandbox-lease-scope-providerleaseid-is","errorCode":null,"errorMessage":"Daytona sandbox lease ${scope.providerLeaseId} is no longer active.","messagePattern":"Daytona sandbox lease (.+?) is no longer active\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/plugin.ts","lineNumber":1038,"sourceCode":"  function isClosed(scope: SandboxScope): boolean {\n    return states.get(key(scope)) === true;\n  }\n\n  function reset(): void {\n    states.clear();\n  }\n\n  return { open, close, isClosed, reset };\n})();\n\nasync function withSandboxActivityGate<T>(\n  scope: SandboxScope,\n  fn: () => Promise<T>,\n  options: SandboxLeaseAdmissionOptions = {},\n): Promise<T> {\n  while (true) {\n    if (!options.allowClosed && sandboxHandleLeaseAdmissionStates.isClosed(scope)) {\n      throw new Error(`Daytona sandbox lease ${scope.providerLeaseId} is no longer active.`);\n    }\n\n    const teardownGate = sandboxHandleTeardownGates.current(scope);\n    if (teardownGate) {\n      await teardownGate.promise;\n      if (!options.allowClosed && sandboxHandleLeaseAdmissionStates.isClosed(scope)) {\n        throw new Error(`Daytona sandbox lease ${scope.providerLeaseId} is no longer active.`);\n      }\n      continue;\n    }\n\n    const activityGate = await sandboxHandleActivityGates.begin(scope);\n    try {\n      // A teardown can still begin between the initial check above and the\n      // activity-gate admission. If that happens, back out and wait for the\n      // teardown to finish instead of proceeding into a race with cleanup.\n      if (sandboxHandleTeardownGates.current(scope)) {\n        continue;","sourceCodeStart":1020,"sourceCodeEnd":1056,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/daytona/src/plugin.ts#L1020-L1056","documentation":"Thrown by withSandboxActivityGate at loop entry when the lease admission state is closed (and allowClosed is not set). This is the first of three identical-throw sites in the gate loop; it blocks any new activity on a lease that is no longer active before checking teardown/activity gates.","triggerScenarios":"Any sandbox operation routed through withSandboxActivityGate is attempted on a lease that sandboxHandleLeaseAdmissionStates marks closed, with options.allowClosed falsy. This site fires at the top of the while loop before any gate interaction.","commonSituations":"A concurrent teardown/destroy closed the lease while another caller still holds a reference and issues an operation; a lease was released upstream but a queued task still runs; retry logic re-entering after the lease closed during a wait.","solutions":["Stop issuing operations against the lease after release/destroy; cancel queued tasks on teardown.","If the operation must run, acquire a new lease and re-dispatch.","Pass options.allowClosed only if the operation is intentionally tolerant of a closed lease (rare).","Audit for code paths that retain a scope past lease release."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await withSandboxActivityGate(scope, () => op(), { allowClosed: false });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('no longer active')) {\n    // lease closed at entry; re-acquire or abort this task\n  }\n  throw e;\n}","preventionTips":["Cancel queued operations when a lease is released/destroyed.","Do not retry against the same closed lease; acquire a new one.","Treat 'no longer active' as terminal for the given providerLeaseId."],"tags":["daytona","sandbox","lease","lifecycle","concurrency"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}