{"record":{"id":"2c5e382d23ce819a","repo":"paperclipai/paperclip","slug":"environment-driver-driver-driver-does-not-support-orphan","errorCode":null,"errorMessage":"Environment driver \"${driver.driver}\" does not support orphan sandbox teardown.","messagePattern":"Environment driver \"(.+?)\" does not support orphan sandbox teardown\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/environment-runtime.ts","lineNumber":3839,"sourceCode":"\n      return released;\n    },\n\n    // Tear an orphan ephemeral sandbox down from its recorded provider config.\n    // A failed acquire records the orphan as a `pending_cleanup` lease. The row\n    // keeps the provider, the provider lease id, and the sandbox config, so this\n    // teardown runs without the environment row and accepts a null environment.\n    // The teardown resolves the recorded secret refs through the durable orphan\n    // record, so a deleted or foreign-bound environment never strands it. The\n    // caller owns the lease release; this dispatcher only runs the provider\n    // teardown and throws when the driver teardown throws.\n    async retryPendingSandboxTeardown(input: {\n      environment: Environment | null;\n      lease: EnvironmentLease;\n    }): Promise<unknown> {\n      const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));\n      if (!driver.retryPendingSandboxTeardown) {\n        throw new Error(\n          `Environment driver \"${driver.driver}\" does not support orphan sandbox teardown.`,\n        );\n      }\n      return await driver.retryPendingSandboxTeardown(input);\n    },\n\n    // Report whether the provider worker can run an orphan teardown now. The\n    // cleanup sweep calls this before it claims a finite retry attempt, so a\n    // briefly-down plugin worker never burns an attempt. This dispatcher never\n    // throws: an unregistered driver, or a driver with no probe, reports ready,\n    // so the teardown still runs and its own failure counts toward the cap.\n    async isPendingCleanupWorkerReady(input: {\n      environment: Environment | null;\n      lease: EnvironmentLease;\n    }): Promise<boolean> {\n      const driver = getDriver(getLeaseDriverKey(input.lease, input.environment));\n      if (!driver?.isPendingCleanupWorkerReady) return true;\n      return driver.isPendingCleanupWorkerReady(input);","sourceCodeStart":3821,"sourceCodeEnd":3857,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/environment-runtime.ts#L3821-L3857","documentation":"retryPendingSandboxTeardown delegates to the environment driver resolved from the lease. Not all drivers implement retryPendingSandboxTeardown (it is optional); when the resolved driver lacks it, the runtime throws 'Environment driver \"X\" does not support orphan sandbox teardown.'","triggerScenarios":"Invoking orphan sandbox teardown retry for a lease whose driver (e.g., a driver without sandbox lifecycle support) has no retryPendingSandboxTeardown implementation.","commonSituations":"Switching an environment between drivers (e.g., local vs cloud) and then retrying teardown recorded under the old driver; admin/recovery tooling that calls teardown retry unconditionally for all leases.","solutions":["Route the retry to the driver that originally owned the sandbox (fix getLeaseDriverKey/lease metadata)","Upgrade or select a driver that supports orphan sandbox teardown","Skip teardown-retry for drivers that don't support it — check driver.retryPendingSandboxTeardown before calling"],"exampleFix":"// before\nawait runtime.retryPendingSandboxTeardown({ environment, lease });\n// after\nconst key = getLeaseDriverKey(lease, environment);\nif (driverSupportsTeardown(key)) await runtime.retryPendingSandboxTeardown({ environment, lease });\nelse logger.warn({ leaseId: lease.id }, 'driver does not support orphan teardown');","handlingStrategy":"validation","validationCode":"const key = getLeaseDriverKey(lease, environment);\nconst driver = getDriver(key);\nif (!driver?.retryPendingSandboxTeardown) {\n  console.warn(`Driver ${key} cannot retry orphan sandbox teardown; skipping`);\n}","typeGuard":"function supportsTeardown(d: EnvironmentDriver): d is EnvironmentDriver & Required<Pick<EnvironmentDriver, \"retryPendingSandboxTeardown\">> {\n  return typeof d.retryPendingSandboxTeardown === \"function\";\n}","tryCatchPattern":"try {\n  await runtime.retryPendingSandboxTeardown({ environment, lease });\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"does not support orphan sandbox teardown\")) {\n    // skip or manually clean the sandbox via the owning driver\n  } else throw e;\n}","preventionTips":["Check driver capability flags before invoking optional driver operations","Keep lease driver keys in sync when migrating environments between drivers","Filter recovery/cleanup jobs to teardown-capable drivers","Add capability introspection to driver registries instead of relying on throw-on-call"],"tags":["sandbox","drivers","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}