paperclipai/paperclip · error

${action} timed out: ${result.stderr.trim()}

Error message

${action} timed out: ${result.stderr.trim()}

What it means

Thrown by the Cloudflare bridge's `requireZeroExit` (routes.ts:118) when a lease-utility command (mkdir workspace, write/verify sentinel) returns `timedOut: true`. The wrapper `executeInSandbox` converts SDK timeout errors into a result with `timedOut: true` and a stderr message, and `requireZeroExit` surfaces that as a timed-out action error with the stderr detail.

Source

Thrown at packages/plugins/sandbox-providers/cloudflare/bridge-template/src/routes.ts:118

  },
  command: string,
  args: string[],
  cwd = "/",
) {
  return await executeInSandbox({
    sandbox,
    command,
    args,
    cwd,
    timeoutMs: options.timeoutMs,
    sessionStrategy: options.sessionStrategy,
    sessionId: options.sessionId,
  });
}

function requireZeroExit(action: string, result: { exitCode: number | null; timedOut: boolean; stderr: string }) {
  if (result.timedOut) {
    throw new Error(`${action} timed out: ${result.stderr.trim()}`);
  }
  if (result.exitCode !== 0) {
    throw new Error(
      `${action} failed with exit code ${result.exitCode ?? "null"}${result.stderr.trim() ? `: ${result.stderr.trim()}` : ""}`,
    );
  }
}

async function ensureWorkspace(
  sandbox: CloudflareSandbox,
  options: {
    remoteCwd: string;
    sessionStrategy: SessionStrategy;
    sessionId: string;
    timeoutMs: number;
  },
) {
  const result = await execLeaseUtility(sandbox, options, "mkdir", ["-p", options.remoteCwd], "/");

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Increase `timeoutMs` in the acquire/probe/resume request body to accommodate sandbox cold-start.
  2. Retry the lease acquire/resume — cold-start latency is often transient on the second attempt.
  3. If persistent, check Cloudflare sandbox service health and the bridge deployment region.

Example fix

// before
{ method: "POST", body: JSON.stringify({ environmentId, runId, timeoutMs: 5000 }) }
// after
{ method: "POST", body: JSON.stringify({ environmentId, runId, timeoutMs: 60000 }) }
Defensive patterns

Strategy: retry

Validate before calling

// Choose a timeout that tolerates cold start before the request.
function leaseTimeoutMs(attempt) {
  const base = 30000;
  return attempt === 0 ? base : base * (attempt + 1); // 30s, 60s, 90s
}

Try / catch

async function acquireWithRetry(client, body, attempts = 3) {
  let lastErr;
  for (let i = 0; i < attempts; i++) {
    try {
      return await client.acquireLease({ ...body, timeoutMs: leaseTimeoutMs(i) });
    } catch (err) {
      lastErr = err;
      if (err instanceof Error && err.message.includes("timed out")) continue;
      throw err;
    }
  }
  throw lastErr;
}

Prevention

When it happens

Trigger: During `/leases/acquire`, `/leases/resume`, or `/probe`, an internal setup command (`mkdir -p <remoteCwd>`, sentinel write/verify) exceeds the `timeoutMs` window configured for the request (default `DEFAULT_TIMEOUT_MS`). Slow/cold-starting sandboxes or a frozen filesystem make the SDK's exec timeout trip.

Common situations: Cloudflare sandbox cold start adds latency that pushes the first mkdir/sentinel past the default timeout; an overloaded Workers/edge environment; or the caller set a very low `timeoutMs`.

Understand the failure class

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/6b09cf4265481afd. Report an issue: GitHub.