JuliusBrussee/caveman · error · AgentMcpHTTPError
cave_agent_tool_timeout | cave_network_error
cave_agent_tool_timeout | cave_network_error
Error message
${timedOut ? `Caveman API request timed out after ${agentMcpTimeoutMS()}ms.` : error instanceof Error ? error.message : "Caveman API request failed."} What it means
This error is thrown by agentMcpRequest() when a fetch call to the Caveman API at cfg.baseURL fails at the transport level. If the failure is a TimeoutError the code is cave_agent_tool_timeout and the message reports the configured timeout from agentMcpTimeoutMS(); any other network failure (DNS, refused connection, TLS, socket reset) yields cave_network_error with the underlying error message. It wraps every non-HTTP-level failure of the Caveman agent MCP HTTP client.
Solutions
- Verify the Caveman gateway is running and reachable: curl ${baseURL} from the same host.
- Check the baseURL/gateway URL configuration (env vars like CAVEMAN_LISTEN / gateway URL) for typos in host or port.
- If timeouts, raise the MCP tool timeout via agentMcpTimeoutMS() configuration or investigate slow backend endpoints.
- Check network/proxy/firewall settings; ensure the gateway port is not blocked.
- Retry the tool call if the failure was transient (e.g. restarting gateway).
Example fix
// before (gateway down)
const res = await agentMcpRequest("POST", "/v1/agent/run", body); // throws cave_network_error
// after
gatewayHostPort check / start gateway:
// caveman gateway start
const res = await agentMcpRequest("POST", "/v1/agent/run", body); Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: check gateway reachability before issuing agent tool calls
const { host, port } = gatewayHostPort();
const reachable = await fetch(`http://${host}:${port}/`, { signal: AbortSignal.timeout(2000) })
.then(r => r.ok).catch(() => false);
if (!reachable) throw new Error(`Caveman gateway unreachable at ${host}:${port}; start it first`); Type guard
function isCavemanNetworkError(e: unknown): e is { name: "AgentMcpHTTPError"; code: string; message: string } {
return e instanceof Error && (e as { code?: string }).code === "cave_network_error"
|| (e instanceof Error && e.name === "TimeoutError");
} Try / catch
try {
await agentMcpRequest("POST", path, body);
} catch (e) {
if (e instanceof Error && e.name === "TimeoutError") {
// retry with backoff or raise timeout
} else if (isCavemanNetworkError(e)) {
console.error("Gateway unreachable:", e.message); // check gateway is running
} else throw e;
} Prevention
- Start/health-check the Caveman gateway before invoking agent tools
- Validate baseURL/gateway host:port config at startup
- Set the MCP tool timeout (agentMcpTimeoutMS) to a realistic value for your workload
- Monitor network/proxy changes in CI environments
When it happens
Trigger: fetch() rejects before a response is received: request exceeded agentMcpTimeoutMS() abort (name === 'TimeoutError'), gateway unreachable/Connection refused, DNS failure, TLS handshake failure, or the socket reset mid-request on any POST/GET to `${cfg.baseURL}${path}`.
Common situations: Caveman gateway not running or wrong baseURL configured, CAVEMAN agent tools called from a CLI session whose gateway has crashed, corporate proxy/firewall blocking the endpoint, slow backend exceeding the MCP tool timeout, or typo'd port in the gateway URL.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- AbortError
- awscreds: request failed
- awscreds: sts assume role with web identity failed
- binary download failed: HTTP
- cave_request_failed
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e428b65d1a38d3ca.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:18394
);
}
let response: Response;
try {
const request: RequestInit = {
method: options.method ?? "GET",
signal: AbortSignal.timeout(agentMcpTimeoutMS()),
headers: {
authorization: `Bearer ${cfg.token}`,
...(options.method === "POST"
? { "content-type": "application/json", "x-cave-csrf": "cli" }
: {}),
},
};
if (options.method === "POST") request.body = JSON.stringify(options.body ?? {});
response = await fetch(`${cfg.baseURL}${path}`, request);
} catch (error) {
const timedOut = error instanceof Error && error.name === "TimeoutError";
throw new AgentMcpHTTPError(
timedOut
? `Caveman API request timed out after ${agentMcpTimeoutMS()}ms.`
: error instanceof Error
? error.message
: "Caveman API request failed.",
timedOut ? "cave_agent_tool_timeout" : "cave_network_error",
);
}
const body = await response.json().catch(() => ({})) as JSONObject;
if (!response.ok) {
const envelope = body.error && typeof body.error === "object" && !Array.isArray(body.error)
? body.error as Record<string, unknown>
: {};
const flatCode = typeof body.error === "string" ? body.error : undefined;
throw new AgentMcpHTTPError(
typeof envelope.message === "string"
? envelope.message
: typeof body.message === "string"View on GitHub (pinned to 3ee70a1026)