paperclipai/paperclip · error · ExeDevApiError

exe.dev API command failed (${response.status}) for: ${logCo

Error message

exe.dev API command failed (${response.status}) for: ${logCommand}

What it means

Thrown as ExeDevApiError by runLifecycleCommand when the POST to config.apiUrl returns a non-2xx response. The error carries .status (the HTTP code) and .body (the raw response text) so callers can branch on the cause. The logCommand in the message is the redacted command string (redactCreateCommand strips --env, --prompt, --setup-script values) to keep secrets out of logs.

Source

Thrown at packages/plugins/sandbox-providers/exe-dev/src/plugin.ts:388

}

async function runLifecycleCommand(
  config: ExeDevDriverConfig,
  command: string,
  logCommand = command,
): Promise<unknown> {
  const response = await fetch(config.apiUrl, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${resolveApiKey(config)}`,
      "Content-Type": "text/plain; charset=utf-8",
    },
    body: command,
    signal: AbortSignal.timeout(Math.min(config.timeoutMs, EXE_DEV_API_MAX_TIMEOUT_MS)),
  });
  const body = await response.text();
  if (!response.ok) {
    throw new ExeDevApiError(
      `exe.dev API command failed (${response.status}) for: ${logCommand}`,
      response.status,
      body,
    );
  }

  const trimmed = body.trim();
  if (!trimmed) return null;
  try {
    return JSON.parse(trimmed);
  } catch {
    return body;
  }
}

function parseVmRecord(value: unknown, depth = 0): ExeDevVmRecord | null {
  if (depth > MAX_VM_RECORD_DEPTH) return null;
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Inspect error.status and error.body: 401/403 -> fix the API key (EXE_API_KEY or config.apiKey); 404 -> correct apiUrl; 400 -> correct command flags/image.
  2. For 5xx or transient network errors, retry with backoff (the provider already enforces AbortSignal.timeout capped by EXE_DEV_API_MAX_TIMEOUT_MS).
  3. Print the redacted logCommand from the error message to see which lifecycle op and flags failed without leaking secrets.

Example fix

// before
await runLifecycleCommand(config, cmd);

// after
try {
  await runLifecycleCommand(config, cmd);
} catch (err) {
  if (err instanceof ExeDevApiError) {
    log.error({ status: err.status, body: err.body }, 'exe.dev lifecycle failed');
    if (err.status === 401 || err.status === 403) throw new Error('exe.dev auth failed');
    if (err.status >= 500) throw new RetryableError(err.message);
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isExeDevConfigValid(config: ExeDevDriverConfig): string | null {
  if (!config.apiUrl || !/^https?:\/\//.test(config.apiUrl)) return 'apiUrl missing/invalid';
  if (!(config.apiKey || process.env.EXE_API_KEY)) return 'apiKey missing';
  return null;
}

Type guard

function isExeDevApiError(x: unknown): x is { status: number; body: string; message: string } {
  return x instanceof Error && (x as { name?: string }).name === 'ExeDevApiError';
}

Try / catch

try {
  await runLifecycleCommand(config, cmd);
} catch (err) {
  if (err instanceof Error && (err as { name?: string }).name === 'ExeDevApiError') {
    const e = err as { status: number; body: string };
    if (e.status === 401 || e.status === 403) throw new Error('exe.dev auth failed');
    if (e.status >= 500) throw new RetryableError(e.body || 'exe.dev 5xx');
    throw new Error(`exe.dev ${e.status}: ${e.body}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: exe.dev API rejecting the lifecycle command: 401/403 from a bad or expired API key, 404 from a wrong apiUrl, 400 from a malformed command (bad image/name/flags), 5xx from an exe.dev outage, or a timeout surfaced as a non-OK response.

Common situations: API key revoked or rotated but config not updated; apiUrl pointing at the wrong endpoint; vm name over 63 chars from buildVmName colliding with an existing name; image/command flags not supported by the exe.dev CLI version; transient exe.dev 5xx during a deploy.

Related errors


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