paperclipai/paperclip · error · ToolGatewayHttpError
error.reasonCode
error.reasonCode
Error message
error.message
What it means
This is the generic rethrow branch for ToolGatewayHttpError inside the remote tools/call handler: the existing error is rewrapped preserving status, message, and reasonCode while enriching details with the current execution record (error.details.execution ?? execution) and the connection/catalog context. Like error 493, message and code are dynamic and mirror the original thrown ToolGatewayHttpError.
Solutions
- Inspect error.reasonCode and error.details (connectionId, catalogEntryId, execution) to find the root cause instead of the generic message.
- Fix the underlying issue indicated by the reason code (config, credentials, handle, or endpoint).
- Use the attached execution record to see request endpoint/protocol and how far the call progressed.
- Retry only for transient reason codes (timeouts, 5xx); configuration/auth codes require corrective action first.
Example fix
// before
catch (e) { console.log(e.message); } // 'error.message' tells little
// after
catch (e) {
console.error(e.reasonCode, e.details.connectionId, e.details.execution);
if (e.reasonCode === "railway_api_not_verified") await reverifyRailway(e.details.connectionId);
} Defensive patterns
Strategy: try-catch
Type guard
const isToolGatewayError = (e) => e instanceof ToolGatewayHttpError || (typeof e.reasonCode === "string" && typeof e.status === "number");
Try / catch
try {
return await gateway.invoke({ method: "tools/call", params });
} catch (e) {
if (isToolGatewayError(e)) {
switch (e.reasonCode) {
case "railway_api_not_verified": return reverifyAndRetry(e);
case "vercel_connect_unavailable": return configureVercelConnectAndRetry(e);
case "request_timeout": return retryWithBackoff(e);
default: throw e;
}
}
throw e;
} Prevention
- Branch handling on reasonCode and details, not the message string, since messages are dynamic.
- Log e.details.execution to diagnose where remote calls fail.
- Treat this rethrow as pass-through: fix the root reason code rather than retrying blindly.
- Retry only transient reason codes; treat config/auth codes as actionable alerts.
When it happens
Trigger: Any ToolGatewayHttpError thrown deeper in the remote MCP tools/call flow — e.g. mcp_*_not_found, railway_api_not_verified, vercel_connect_unavailable, request timeouts, auth failures — reaches this catch block and is rethrown with execution metadata attached.
Common situations: Debugging a failed tool execution and inspecting the enriched details (connectionId, catalogEntryId, execution trace); duplicate wrapping is prevented by reusing the original execution when already present.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- error.code
- grant_audience_denied
- local_stdio_missing_secret
- mcp_${kind}_not_found
- mcp_transport_unsupported
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/f764b3e2a7db3af6.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:6124
: null;
const result = normalizeMcpToolResult(
payloadRecord.result,
"mcp_http",
false,
sourceTemplateKey,
);
await markRemoteConnectionHealth(
connection,
"ok",
"Remote MCP server responded to tools/call.",
);
return { result, headerSummary, execution };
} catch (error) {
if (error instanceof RailwayError) {
throw new ToolGatewayHttpError(error.status, error.message, error.code, { connectionId: connection.id, catalogEntryId: entry.id, execution });
}
if (error instanceof ToolGatewayHttpError) {
throw new ToolGatewayHttpError(
error.status,
error.message,
error.reasonCode,
{
...error.details,
execution: error.details.execution ?? execution,
},
);
}
if (error instanceof Error && error.name === "AbortError") {
await markRemoteConnectionHealth(
connection,
"error",
"Remote MCP tool call timed out.",
);
throw new ToolGatewayHttpError(
504,
"Remote MCP tool call timed out",View on GitHub (pinned to 3f1d897a7c)