paperclipai/paperclip · error · Error

Command is not executable: "${command}" (resolved: "${absolu

Error message

Command is not executable: "${command}" (resolved: "${absolute}")

What it means

Thrown by ensureCommandResolvable when the command string contains a path separator ('/' or '\\') so it is treated as a path to an executable, but resolveCommandPath could not resolve it as runnable. The resolved absolute path is included so the caller can see exactly what was attempted. This covers the case where a user points at a specific binary file that is missing, not executable, or wrong-arch.

Source

Thrown at packages/adapter-utils/src/server-utils.ts:3190

export async function ensureCommandResolvable(
  command: string,
  cwd: string,
  env: NodeJS.ProcessEnv,
  options: {
    remoteExecution?: RemoteExecutionSpec | null;
  } = {},
) {
  if (options.remoteExecution) {
    const resolvedSsh = await resolveCommandPath("ssh", process.cwd(), env);
    if (resolvedSsh) return;
    throw new Error('Command not found in PATH: "ssh"');
  }
  const resolved = await resolveCommandPath(command, cwd, env);
  if (resolved) return;
  if (command.includes("/") || command.includes("\\")) {
    const absolute = path.isAbsolute(command) ? command : path.resolve(cwd, command);
    throw new Error(`Command is not executable: "${command}" (resolved: "${absolute}")`);
  }
  throw new Error(`Command not found in PATH: "${command}"`);
}

export async function runChildProcess(
  runId: string,
  command: string,
  args: string[],
  opts: {
    cwd: string;
    env: Record<string, string>;
    timeoutSec: number;
    graceSec: number;
    onLog: (stream: "stdout" | "stderr", chunk: string) => Promise<void>;
    onLogError?: (err: unknown, runId: string, message: string) => void;
    onSpawn?: (meta: { pid: number; processGroupId: number | null; startedAt: string }) => Promise<void>;
    terminalResultCleanup?: TerminalResultCleanupOptions;
    stdin?: string;

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Check the resolved absolute path in the message exists and is executable: ls -l <absolute> and chmod +x if needed.
  2. Correct the agentCommand / command config to point at the real binary location for this host.
  3. If using a relative path, confirm the cwd passed to ensureCommandResolvable is the one the path is relative to.
  4. Reinstall the agent CLI so the expected binary path is populated.

Example fix

// before
await ensureCommandResolvable("./bin/claude", cwd, env);
// after
await ensureCommandResolvable("/usr/local/bin/claude", cwd, env);
// and: chmod +x /usr/local/bin/claude
Defensive patterns

Strategy: validation

Validate before calling

async function ensureExecutable(command, cwd, env) {
  if (command.includes("/") || command.includes("\\")) {
    const abs = path.isAbsolute(command) ? command : path.resolve(cwd, command);
    await fs.access(abs, fs.constants.X_OK);
  }
}
await ensureExecutable(command, cwd, env);
await ensureCommandResolvable(command, cwd, env, options);

Prevention

When it happens

Trigger: Calling ensureCommandResolvable('./node_modules/.bin/claude', cwd, env) where that file does not exist relative to cwd, or '/usr/local/bin/agent' that is not present or lacks execute permission. Because the command contains '/', resolveCommandPath fails and the branch reports the resolved absolute path.

Common situations: A configured agentCommand path that was correct on one host but not another; a binary that exists but is not chmod +x; a Windows backslash path used on Linux or vice versa; a relative ./bin path run from the wrong cwd.

Related errors


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