JuliusBrussee/caveman · error · CaveRequestError
cave request failed ( )
Error message
cave request failed (${response.status}) What it means
This is the generic non-2xx response error for SDK calls routed through the shared caveFetch helper. When the Cave server answers any /sdk/v1/* request with an HTTP status outside 200-299, the body is discarded and a CaveRequestError carrying the numeric status and request path is thrown. It is the library's way of surfacing server-side failures (auth rejection, not found, server error) as a typed error instead of leaking the raw fetch Response.
Solutions
- Log err.status and err.path (CaveRequestError fields) to identify which endpoint and HTTP status failed
- Check Cave service health and that cave.options.baseURL points at the correct environment
- Verify API credentials/keys are valid and not expired (401/403 statuses)
- For 5xx statuses, retry with backoff; for 429, honor rate limits before retrying
Example fix
// before
const result = await sdk.postLabel(input); // throws unhandled CaveRequestError
// after
try {
const result = await sdk.postLabel(input);
} catch (err) {
if (err instanceof CaveRequestError) {
console.error(`cave ${err.path} failed with ${err.status}`);
if (err.status >= 500 || err.status === 429) return retryWithBackoff();
}
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!cave.options.baseURL.startsWith('http')) throw new Error('baseURL must be an absolute URL'); Type guard
function isCaveRequestError(e: unknown): e is CaveRequestError { return e instanceof CaveRequestError; } Try / catch
try { const r = await sdk.someCall(); } catch (e) { if (e instanceof CaveRequestError) { if (e.status >= 500 || e.status === 429) return retry(); if (e.status === 401 || e.status === 403) return refreshCredentials(); throw e; } throw e; } Prevention
- Always catch CaveRequestError around SDK calls rather than generic Error
- Branch on err.status before deciding to retry (5xx/429 retry, 4xx fix request)
- Monitor baseURL configuration per environment (dev/staging/prod)
- Keep cave credentials rotation handled with a refresh path
When it happens
Trigger: Any SDK method that performs a JSON-object request (e.g. artifact list/post, label operations) where the Cave service returns 400/401/404/429/5xx. Specific triggers: expired or wrong cave key (401), unknown artifact or workflow path (404), server-side handler crash (500), rate limiting (429).
Common situations: Deployed Cave service misconfigured or down; API base URL pointing at the wrong environment (staging vs prod); auth credentials rotated while the client is still running; calling a path that does not exist in the deployed server version.
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
- cave_request_failed
- registration failed: HTTP
- tool search failed with HTTP
- awscreds: sts assume role with web identity failed
- binary download failed: HTTP
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/7c01b7e4f5a5166f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/typescript/src/index.ts:2123
}
export class CaveRequestError extends Error {
constructor(readonly status: number, readonly path: string, message: string) {
super(message);
this.name = "CaveRequestError";
}
}
async function request(cave: Cave, path: string, body?: unknown, workflow?: string, trace?: TraceContext, extraHeaders?: Record<string, string>): Promise<Record<string, unknown>> {
const init: RequestInit = {
method: body === undefined ? "GET" : "POST",
headers: { ...headers(cave, workflow ?? cave.options.defaultWorkflow ?? "unlabeled-workflow", undefined, undefined, trace), ...extraHeaders }
};
if (body !== undefined) init.body = JSON.stringify(body);
const response = await caveFetch(cave, `${cave.options.baseURL}${path}`, init);
if (!response.ok) {
discardResponse(response);
throw new CaveRequestError(response.status, path, `cave request failed (${response.status})`);
}
let decoded: unknown;
try {
if (typeof response.text === "function") {
decoded = JSON.parse(await response.text());
} else if (typeof response.json === "function") {
decoded = await response.json();
} else {
throw new Error("missing response decoder");
}
} catch {
throw new CaveRequestError(response.status, path, "cave response was not valid JSON");
}
if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded)) {
throw new CaveRequestError(response.status, path, "cave response must be a JSON object");
}
return decoded as Record<string, unknown>;
}View on GitHub (pinned to 3ee70a1026)