paperclipai/paperclip · error · Error
Timed out checking command "${command}" on sandbox target.
Error message
Timed out checking command "${command}" on sandbox target. What it means
Thrown by ensureSandboxCommandResolvable when the initial `command -v <cmd>` probe inside a sandbox execution target does not return within the configured timeout (target.timeoutMs or 15s default). The sandbox runner wraps the probe in `sh -c`, so a timeout means the sandbox lease is unresponsive, network-stalled, or the shell environment is broken. This fires BEFORE any install command is attempted.
Source
Thrown at packages/adapter-utils/src/execution-target.ts:522
}
async function ensureSandboxCommandResolvable(
command: string,
target: AdapterSandboxExecutionTarget,
installCommand: string | null,
timeoutSec?: number | null,
): Promise<void> {
// Probe whether the binary is resolvable inside the sandbox. We previously
// short-circuited this for sandbox targets, which let the caller report a
// success message even when the CLI was missing from the image. Now we run
// a real `command -v` through the same runner the hello probe will use, so
// the first step honestly reflects whether the binary is on PATH. The
// sandbox provider is responsible for sourcing login profiles (e2b mirrors
// SSH's buildSshSpawnTarget) so this and the hello probe agree on PATH.
let probe = await probeSandboxCommandResolvable(command, target);
if (probe.resolved) return;
if (probe.timedOut) {
throw new Error(`Timed out checking command "${command}" on sandbox target.`);
}
// If the caller supplied an install command, attempt the install once via
// the sandbox runner (which the sandbox provider wraps in a login shell)
// and re-probe before reporting failure. This lets fresh sandbox leases
// bring up the CLI before the resolvability gate, mirroring the test path.
let installFailureDetail: string | null = null;
if (installCommand) {
const runner = requireSandboxRunner(target);
const installTimeoutMs =
typeof timeoutSec === "number" && Number.isFinite(timeoutSec) && timeoutSec > 0
? Math.floor(timeoutSec * 1000)
: target.timeoutMs ?? 300_000;
try {
const installResult = await runner.execute({
command: "sh",
args: shellCommandArgs(installCommand),
cwd: target.remoteCwd,View on GitHub (pinned to 67001ec6eb)
Solutions
- Increase target.timeoutMs (or the caller's timeoutSec) to give the cold sandbox lease more time to respond.
- Verify the sandbox lease is healthy — check provider dashboard/logs for the lease ID and confirm the VM is running and reachable.
- Ensure the sandbox provider sources login profiles correctly so the shell does not hang waiting on interactive profile prompts.
- Retry the operation after recycling the sandbox lease if the provider reports the lease as stale.
Example fix
// before
const target: AdapterSandboxExecutionTarget = {
kind: "remote",
transport: "sandbox",
remoteCwd: "/workspace",
timeoutMs: 5_000, // too short for cold start
};
// after
const target: AdapterSandboxExecutionTarget = {
kind: "remote",
transport: "sandbox",
remoteCwd: "/workspace",
timeoutMs: 30_000, // allow time for lease warm-up
}; Defensive patterns
Strategy: retry
Validate before calling
// Pre-check sandbox lease health before probing commands
async function isSandboxResponsive(target: AdapterSandboxExecutionTarget): Promise<boolean> {
const runner = requireSandboxRunner(target);
try {
const result = await runner.execute({
command: "sh",
args: ["-c", "echo ok"],
cwd: target.remoteCwd,
timeoutMs: Math.min(target.timeoutMs ?? 15_000, 10_000),
});
return !result.timedOut && (result.exitCode ?? 1) === 0;
} catch {
return false;
}
} Try / catch
try {
await ensureSandboxCommandResolvable(command, target, installCommand, timeoutSec);
} catch (err) {
if (err instanceof Error && err.message.includes("Timed out checking command")) {
// Sandbox may still be warming up — recycle lease and retry once
await recycleSandboxLease(target);
await ensureSandboxCommandResolvable(command, target, installCommand, timeoutSec);
} else {
throw err;
}
} Prevention
- Set target.timeoutMs high enough for cold sandbox lease startup (at least 15-30s).
- Warm up sandbox leases before assigning agent work by running a simple echo probe.
- Monitor sandbox provider health metrics and recycle stale leases proactively.
When it happens
Trigger: Calling ensureSandboxCommandResolvable(command, target, installCommand, timeoutSec) where target.kind === 'remote' && target.transport === 'sandbox'. The probeSandboxCommandResolvable helper runs `sh -c 'command -v <cmd>'` via the sandbox runner's execute() with timeoutMs = target.timeoutMs ?? 15_000; that call returns { timedOut: true }.
Common situations: Sandbox provider (e2b or similar) lease is still warming up or has died; sandbox network proxy is blocking the exec channel; the sandbox image has a broken login shell that hangs on startup; target.timeoutMs is set too low for a cold lease; the sandbox host is under heavy load.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timed out while installing the adapter runtime command via:
- Command "${command}" is not installed or not on PATH in the
- Failed to install the adapter runtime command via: ${install
- Timed out checking working directory on remote target: "${cw
- Failed to start sandbox ACP process session bridge: ${startR
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/7dafc1f70aab73bb.
Report an issue: GitHub.