paperclipai/paperclip · error

OpenCode API request failed

Error message

OpenCode API ${path} request failed: ${redact(String(error), runtime.sensitiveValues)}

What it means

Wraps any low-level failure of a request to the OpenCode HTTP API (fetch throwing — connection refused, DNS failure, TLS error, abort) into a single message including the request path. The error string is passed through redact() with the runtime's sensitive values so secrets are not leaked.

Solutions

  1. Read the wrapped cause in the message (e.g. ECONNREFUSED) and verify the OpenCode server is running at the expected base URL/port.
  2. Re-run the health check against the same baseUrl to confirm the server is still alive.
  3. Check for startup races — ensure the server child process is fully listening before issuing API calls.
  4. If the message contains a redaction marker, confirm the underlying error is not leaking credentials and that sensitiveValues is populated.

Example fix

// before
await fetch(`${baseUrl}/session`, { method: "POST" }); // throws raw

// after
try {
  await fetch(`${baseUrl}/session`, { method: "POST" });
} catch (e) {
  if (String(e).includes("ECONNREFUSED")) await restartOpenCodeServer();
  throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

const health = await fetch(`${baseUrl}/health`);
if (!health.ok) throw new Error(`OpenCode server not reachable at ${baseUrl}`);

Try / catch

try {
  await callOpenCodeApi(path, init);
} catch (e) {
  if (e instanceof Error && e.message.includes("request failed")) {
    if (String(e.message).includes("ECONNREFUSED")) await ensureServerRunning();
    else if (String(e.message).includes("abort")) checkTimeouts();
  }
  throw e;
}

Prevention

When it happens

Trigger: The fetch call for `path` throws before a response is received: server not listening, wrong port, connection reset, request aborted, or TLS handshake failure.

Common situations: OpenCode server died between health-check and API use; port collision or the server bound to a different port than recorded in runtime; corporate proxy blocking localhost; ECONNREFUSED during startup races.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/c3daf2ddfb0076ab. Report an issue: GitHub.

Appendix: source

Thrown at packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts:2232

      stage: "typescript_opencode_http_transport",
      ruleId: `opencode.http.${method}.${safeTraceRulePath(path)}`,
      disposition: "operator_only",
      reason: "Sent an exact HTTP request body to the OpenCode app server",
    });
  }
  let response: Response;
  try {
    response = await fetcher(`${runtime.baseUrl}${path}`, {
      ...init,
      signal,
      headers: {
        Authorization: runtime.authHeader,
        "Content-Type": "application/json",
        ...init.headers,
      },
    });
  } catch (error) {
    throw new Error(
      `OpenCode API ${path} request failed: ${redact(String(error), runtime.sensitiveValues)}`,
    );
  }
  const responseRaw = await response.text();
  const responseFrameId = runtime.trace?.frame({
    direction: "provider_to_client",
    raw: responseRaw,
    transport: "http_json",
    nativeMethod: `${method} ${path} ${response.status}`,
  });
  if (!response.ok) {
    if (responseFrameId) {
      runtime.trace?.interpretation({
        frameId: responseFrameId,
        stage: "typescript_opencode_http_parse",
        ruleId: `opencode.http.error.${response.status}`,
        disposition: "rejected",
        reason: `OpenCode API returned HTTP ${response.status}`,

View on GitHub (pinned to 01ad858492)