paperclipai/paperclip · warning

The stopped Daytona sandbox is still settling cancelled…

Error message

The stopped Daytona sandbox is still settling cancelled work. Retry shortly.

What it means

The Daytona sandbox provider throws this when an admission attempt (e.g. re-acquiring/restarting a lease) targets a sandbox that has been confirmed stopped but still has in-flight SDK activity from a previous request settling (cancelled work still draining). Restarting the sandbox under that old request could let it write or execute again, so the provider refuses and asks the caller to retry shortly.

Solutions

  1. Wait briefly and retry the operation — the gate clears once the cancelled work finishes settling.
  2. Add retry with backoff around lease admission when you recently stopped the sandbox.
  3. Ensure your code awaits/cancels in-flight executions before confirming stop so the activity gate is idle before restarting.
  4. If it persists, inspect the activity gate for a leaked active scope (unclosed activity registration) and file/fix the leak.
Defensive patterns

Strategy: retry

Validate before calling

// Check gate state before admission if exposed:
// if (states.isClosed(scope) && gates.isActive(scope)) await waitForSettle(scope);

Try / catch

await retry(async () => admitLease(params), {
  retries: 5,
  factor: 2,
  onRetry: (e) => { if (!/still settling cancelled work/.test(e.message)) throw e; }
});

Prevention

When it happens

Trigger: Calling lease admission/restart (the function building { providerLeaseId, config } around plugin.ts:2221) while sandboxHandleLeaseAdmissionStates.isClosed(scope) is true and sandboxHandleActivityGates.isActive(scope) is true — i.e. a stop was confirmed but an old SDK request is still active.

Common situations: A user cancels/stops work and immediately retries; a supervisor restarts a lease right after stop while a long-running exec still drains; race between stop confirmation and completion of an earlier SDK call.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/a9d4283258d989c9. Report an issue: GitHub.

Appendix: source

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

      throw error;
    }
  },

  async onEnvironmentResumeLease(
    params: PluginEnvironmentResumeLeaseParams,
  ): Promise<PluginEnvironmentLease> {
    const config = parseDriverConfig(params.config);
    const scope: SandboxScope = {
      driverKey: params.driverKey,
      companyId: params.companyId,
      environmentId: params.environmentId,
      providerLeaseId: params.providerLeaseId,
      config,
    };
    // A confirmed stop may precede completion of an old SDK request. Do not
    // restart its sandbox under that request; it could still write or execute.
    if (sandboxHandleLeaseAdmissionStates.isClosed(scope) && sandboxHandleActivityGates.isActive(scope)) {
      throw new Error("The stopped Daytona sandbox is still settling cancelled work. Retry shortly.");
    }
    return await withSandboxActivityGate(scope, async () => {
      const sandbox = await getSandboxOrNull(scope, { bypassTeardownGate: true });
      if (!sandbox) {
        return { providerLeaseId: null, metadata: { expired: true } };
      }

        // A stopped sandbox loses its session shell, so the stored session id is
        // stale after a real restart. Clear the id only when the sandbox is not
        // already running, and clear it before the restart. A stopped sandbox has
        // no live session, so the clear drops a dead id and a later command opens
        // a fresh session. A running sandbox keeps its live session, so the resume
        // leaves the id in place; a concurrent command still finds it and teardown
        // deletes one session. An unconditional clear would drop the id of a live
        // session and leak its shell until sandbox reaping.
        if (sandbox.state !== "started") {
          sandboxHandleSessionStore.clear(scope);
          // A stopped sandbox loses its pseudo-terminals, so a stored duplex channel

View on GitHub (pinned to 3f1d897a7c)