JuliusBrussee/caveman · error
tool search failed with HTTP
Error message
tool search failed with HTTP ${response.status} What it means
HTTP error from the SDK tool-search call: the gateway returned a non-success status for the tool discovery/search request. The status code is included; the failure is server/gateway-side, not a malformed request from the SDK.
Solutions
- Log/check response.status to identify the cause; fix auth headers if 401/403
- Validate the catalog and request body if 400/422 (e.g. schema issues, too many tools)
- Retry with backoff on 429/5xx transient failures
- Verify the Cave backend URL and that the tool-search service is healthy
Example fix
// before
const result = await searchTools(cave, catalog, query);
// after
try {
const result = await searchTools(cave, catalog, query);
} catch (e) {
if (String(e).includes("HTTP 429")) await sleep(backoff);
else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!cave?.baseUrl) throw new Error("cave client not configured before tool search");
if (catalog.length === 0) throw new Error("tool catalog is empty; search would be rejected"); Type guard
null
Try / catch
try {
const result = await searchTools(cave, catalog, query);
} catch (e) {
const m = /HTTP (\d+)/.exec(String(e.message));
if (m && (m[1] === "429" || m[1].startsWith("5"))) { await retryWithBackoff(); }
else if (m && (m[1] === "401" || m[1] === "403")) { refreshCredentials(); }
else throw e;
} Prevention
- Check credentials and backend URL before deploying
- Keep catalog payloads within server limits
- Implement retry with backoff for 429/5xx
- Monitor the tool-search service health
When it happens
Trigger: POST to the tool-search endpoint returns 4xx/5xx: bad API key (401/403), malformed body (400/422), rate limiting (429), or server errors (500+).
Common situations: Expired or wrong Cave credentials; oversized catalog payload rejected by server; tool-search service temporarily down; network proxy returning error pages.
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
- cave request failed ( )
- registration failed: 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/c385930afd714ebd.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/typescript/src/index.ts:1610
};
if (options?.context !== undefined) body["context"] = options.context;
if (options?.maxTools !== undefined) body["max_tools"] = options.maxTools;
if (options?.toolSessionId !== undefined) body["session_id"] = options.toolSessionId;
// Embedding-similarity is a pure passthrough: the SDK forwards the ranker
// choice and the gateway honors "embeddings" only when it has an embedding
// provider wired. The SDK never computes similarity itself (byte-safe, no
// extra deps).
if (options?.ranker !== undefined) body["ranker"] = options.ranker;
const workflow = options?.workflow ?? cave.options.defaultWorkflow ?? "unlabeled-workflow";
const response = await caveFetch(cave, `${cave.options.baseURL}/sdk/v1/tool-search`, {
method: "POST",
headers: headers(cave, workflow),
body: JSON.stringify(body)
});
if (!response.ok) {
discardResponse(response);
throw new Error(`tool search failed with HTTP ${response.status}`);
}
const data = await response.json();
// Map snake_case response to camelCase
const rawSent = strictNonNegativeInt(data.sent_schema_tokens);
const rawFull = strictNonNegativeInt(data.full_schema_tokens);
const validCounts = rawSent !== null && rawFull !== null && rawSent <= rawFull;
const sentSchemaTokens = validCounts ? rawSent : 0;
const fullSchemaTokens = validCounts ? rawFull : 0;
const savedTokens = fullSchemaTokens - sentSchemaTokens;
const reductionPct = fullSchemaTokens === 0 ? 0 : Math.round((savedTokens / fullSchemaTokens) * 1000) / 10;
const catalogByName = new Map<string, CaveTool>();
for (const tool of catalog) {
if (typeof tool.name !== "string" || tool.name.trim() === "" || catalogByName.has(tool.name)) {
throw new Error("tool catalog names must be non-empty and unique");
}
catalogByName.set(tool.name, tool);View on GitHub (pinned to 3ee70a1026)