paperclipai/paperclip · error · Error

Sandbox bridge mode requires a host-side Paperclip API…

Error message

Sandbox bridge mode requires a host-side Paperclip API token.

What it means

Authentication precondition for sandbox bridge mode: the bridge relays sandbox callbacks to the host Paperclip API, which requires a host-side API token, and none was provided on the target configuration.

Solutions

  1. Provide a host-side Paperclip API token for sandbox bridge mode.
  2. Use a non-bridge execution mode if no token is available.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/adapter-utils/src/execution-target.ts:2215 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at packages/adapter-utils/src/execution-target.ts:2511

      // only shorten this wait and suppress the warning below; it never
      // gates, shortens, or replaces the unconditional removal further down.
      // What actually makes the wrapper's own termination deterministic is
      // the wrapper-side session-identity latch, not this event.
      let acknowledgedInTime = false;
      readShutdownAckUntil(Date.now() + DEFAULT_PROCESS_SESSION_SHUTDOWN_WAIT_MS);
      await Promise.race([
        shutdownAcknowledged.then(() => {
          acknowledgedInTime = true;
        }),
        new Promise<void>((resolve) => {
          const budgetTimer = setTimeout(resolve, DEFAULT_PROCESS_SESSION_SHUTDOWN_WAIT_MS);
          budgetTimer.unref?.();
        }),
      ]);
      stopReadingForShutdownAck = true;
      if (!acknowledgedInTime) {
        await onLog(
          "stderr",
          `[paperclip] ACP process session wrapper did not acknowledge shutdown within ${DEFAULT_PROCESS_SESSION_SHUTDOWN_WAIT_MS}ms; removing the session directory anyway.\n`,
        ).catch(() => undefined);
      }
      // Unconditional: this removal runs whether or not the wrapper
      // acknowledged, and whether or not any event (real or forged) arrived
      // under `sessionDir`. `stop()` runs during run teardown and must stay
      // non-fatal, so every step above is best-effort and this step never
      // throws.
      await client.remove(sessionDir).catch(() => undefined);
      await fs.rm(proxyDir, { recursive: true, force: true }).catch(() => undefined);
    },
  };
}

function getProcessSessionProxySource(input: { port: number; token: string }): string {
  return `#!/usr/bin/env node
import net from "node:net";

View on GitHub (pinned to 3f1d897a7c)