JuliusBrussee/caveman · error
filter must be a finite number
Error message
filter ${key} must be a finite number What it means
Numeric range filters (min_cost_usd, max_cost_usd, min_total_tokens, max_total_tokens, min_latency_ms, max_latency_ms) must be finite numbers when present. Non-numbers, NaN, and ±Infinity throw `filter ${key} must be a finite number`.
Solutions
- Pass numbers, not strings: min_cost_usd: 0.5
- Omit the key when you mean "unbounded" instead of using Infinity
- Guard with Number.isFinite before sending; drop or fix non-finite values
- Convert form/query-string input with Number() and validate
Example fix
// before
searchTraces({ filters: { min_cost_usd: '0.5', max_latency_ms: Infinity } });
// after
searchTraces({ filters: { min_cost_usd: 0.5 } }); // omit max_latency_ms for unbounded Defensive patterns
Strategy: validation
Validate before calling
const NUMERIC_FILTERS = ['min_cost_usd','max_cost_usd','min_total_tokens','max_total_tokens','min_latency_ms','max_latency_ms'];
function assertFiniteNumbers(filters) {
for (const key of NUMERIC_FILTERS) {
const v = filters?.[key];
if (v !== undefined && (typeof v !== 'number' || !Number.isFinite(v))) {
throw new Error(`filter ${key} must be a finite number`);
}
}
} Type guard
function isFiniteNumber(v) {
return typeof v === 'number' && Number.isFinite(v);
} Try / catch
try {
await searchTraces({ filters });
} catch (error) {
const m = error.message.match(/^filter (\w+) must be a finite number/);
if (m) {
const n = Number(filters[m[1]]);
if (Number.isFinite(n)) filters[m[1]] = n; else delete filters[m[1]];
}
} Prevention
- Convert form/query-string input with Number() before sending
- Omit range keys for unbounded sides instead of using Infinity
- Guard with Number.isFinite; drop or fix NaN/null values
- Type numeric filters as number | undefined in client code
When it happens
Trigger: Passing { min_cost_usd: "0.5" } (string), { max_latency_ms: Infinity }, { min_total_tokens: NaN }, or null for any of these keys; JSON has no Infinity so it may arrive as null or a string after serialization.
Common situations: String values from form inputs never converted to numbers; NaN from failed parseFloat; Infinity used as "no upper bound" instead of omitting the key; null from JSON.stringify of Infinity.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- filter must be a boolean
- filter must be a non-empty array of non-empty strings
- filter monitor must be an object
- filter status_class values must be 2xx, 4xx, or 5xx
- filters must be an object
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/315ca2f59f94d8be.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/agent-mcp.ts:481
"member_user_id",
"api_key_id",
"optimization_id",
"status_class",
];
for (const key of stringListKeys) {
const value = filters[key];
if (value === undefined) continue;
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== "string" || entry.trim() === "")) {
throw new Error(`filter ${key} must be a non-empty array of non-empty strings`);
}
if (key === "status_class" && value.some((entry) => !["2xx", "4xx", "5xx"].includes(entry as string))) {
throw new Error("filter status_class values must be 2xx, 4xx, or 5xx");
}
}
for (const key of ["min_cost_usd", "max_cost_usd", "min_total_tokens", "max_total_tokens", "min_latency_ms", "max_latency_ms"]) {
const value = filters[key];
if (value !== undefined && (typeof value !== "number" || !Number.isFinite(value))) {
throw new Error(`filter ${key} must be a finite number`);
}
}
for (const key of ["has_error", "compressed"]) {
const value = filters[key];
if (value !== undefined && typeof value !== "boolean") throw new Error(`filter ${key} must be a boolean`);
}
const monitor = filters.monitor;
if (monitor !== undefined) {
if (!monitor || typeof monitor !== "object" || Array.isArray(monitor)) throw new Error("filter monitor must be an object");
const monitorUnknown = Object.keys(monitor).filter((key) => key !== "id" && key !== "verdict");
if (monitorUnknown.length > 0) throw new Error(`filter monitor has unknown key(s): ${monitorUnknown.sort().join(", ")}`);
if (typeof monitor.id !== "string" || monitor.id.trim() === "") throw new Error("filter monitor.id is required");
if (typeof monitor.verdict !== "string" || !["pass", "fail", "error"].includes(monitor.verdict)) {
throw new Error("filter monitor.verdict must be pass, fail, or error");
}
}
}
View on GitHub (pinned to 3ee70a1026)