JuliusBrussee/caveman · error · AgentMcpHTTPError

cave_request_failed

cave_request_failed

Error message

Caveman API request failed (${response.status}).

What it means

Thrown by agentMcpRequest() after receiving an HTTP response with a non-ok status when the response body carries no usable error message or code. The client first tries to surface the API's structured error envelope (body.error.message or body.message) and envelope code; if none is a string it falls back to this generic message with code cave_request_failed. It represents a real HTTP-level failure of a Caveman API call whose server-side detail was lost.

Solutions

  1. Log/inspect response.status and the raw response body to identify the real server error.
  2. Check the gateway version matches the CLI; upgrade the gateway so it returns structured error envelopes.
  3. Verify the request path and payload match the current Caveman API schema.
  4. If it is a proxy error page (502/503), fix the reverse proxy / upstream gateway availability.

Example fix

// before
try { await agentMcpRequest("POST", "/v1/agent/run", body); }
catch (e) { console.log(e.message); } // "Caveman API request failed (502)."
// after
try { await agentMcpRequest("POST", "/v1/agent/run", body); }
catch (e) { console.error(e.message, e.statusCode, await rawBody); } // inspect status + raw body
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(`${baseURL}${path}`);
if (!res.ok) {
  const text = await res.text();
  console.error(`Caveman API ${res.status}:`, text.slice(0, 500)); // inspect real cause
}

Type guard

function isAgentMcpHTTPError(e: unknown): e is Error & { statusCode?: number; code: string } {
  return e instanceof Error && e.name === "AgentMcpHTTPError";
}

Try / catch

try {
  await agentMcpRequest("POST", path, body);
} catch (e) {
  if (isAgentMcpHTTPError(e)) {
    if (e.code === "cave_request_failed") {
      console.error(`HTTP failure (${e.statusCode ?? "?"}): check gateway version and request schema`, e.message);
    }
  } else throw e;
}

Prevention

When it happens

Trigger: Any Caveman API request returning response.ok === false (4xx/5xx) where the parsed JSON body has neither body.error.message, body.message (strings) nor body.error/envelope.code to report.

Common situations: Gateway returning an HTML/plain-text error page (e.g. 502 from a reverse proxy) that fails JSON parse to {}, hitting a wrong path that yields an opaque 404, or an older gateway version not emitting the error envelope.

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


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/d2e0f7f79a0bad97. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/index.ts:18409

    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"
          ? body.message
          : `Caveman API request failed (${response.status}).`,
      typeof envelope.code === "string" ? envelope.code : flatCode ?? "cave_request_failed",
      response.status,
    );
  }
  return body;
}

async function agentMcpProjectId(): Promise<string> {
  const cfg = await config();
  if (cfg.projectId) return cfg.projectId;
  const projects = await agentMcpRequest("/api/v1/projects");
  const projectObject = projects && typeof projects === "object" && !Array.isArray(projects)
    ? projects

View on GitHub (pinned to 3ee70a1026)