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
- Read the wrapped cause in the message (e.g. ECONNREFUSED) and verify the OpenCode server is running at the expected base URL/port.
- Re-run the health check against the same baseUrl to confirm the server is still alive.
- Check for startup races — ensure the server child process is fully listening before issuing API calls.
- 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
- Confirm the server child process is listening before issuing API calls
- Use the port returned by the reservation step, not a hard-coded one
- Set explicit fetch timeouts and handle AbortError distinctly
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
- Anthropic Managed Agents request failed with HTTP ${response
- OpenCode event stream returned HTTP ${response.status}
- OpenCode API ${path} returned HTTP ${response.status}: ${red
- request_failed
- Discord returned an unreadable response
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/c3daf2ddfb0076ab.
Report an issue: GitHub.