paperclipai/paperclip · error

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

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.

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)

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.