JuliusBrussee/caveman · error
filter must be a boolean
Error message
filter ${key} must be a boolean What it means
Validation error from validateTraceFilters in the agent MCP server: a filter key declared as boolean was supplied with a non-boolean value. The MCP client sent JSON whose type does not match the filter contract for that key.
Solutions
- Pass real booleans: has_error: true
- Convert strings with value === 'true' / 'false' before calling
- Omit the key when the flag is unknown rather than passing null
Example fix
// before
searchTraces({ filters: { has_error: 'true' } });
// after
searchTraces({ filters: { has_error: hasError === 'true' } }); Defensive patterns
Strategy: type-guard
Validate before calling
function assertBooleanFilters(filters) {
for (const key of ['has_error', 'compressed']) {
const v = filters?.[key];
if (v !== undefined && typeof v !== 'boolean') {
throw new Error(`filter ${key} must be a boolean`);
}
}
} Type guard
function isBoolean(v) {
return typeof v === 'boolean';
} Try / catch
try {
await searchTraces({ filters });
} catch (error) {
const m = error.message.match(/^filter (\w+) must be a boolean/);
if (m) {
if (filters[m[1]] === 'true') filters[m[1]] = true;
else if (filters[m[1]] === 'false') filters[m[1]] = false;
else delete filters[m[1]];
}
} Prevention
- Parse query-string booleans ('true'/'false') into real booleans at the boundary
- Avoid 0/1 encodings for these flags in UIs
- Omit the key when the value is unknown rather than passing null
- Use strict === true / === false comparisons in client code
When it happens
Trigger: Passing { has_error: 'true' }, { compressed: 1 }, { has_error: null }, or a query-string-derived "false" string.
Common situations: URL query params arriving as strings; UIs emitting 0/1; serialization layers coercing booleans; LLM-generated tool args using the string "true".
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- filter monitor must be an object
- filters must be an object
- filter must be a finite number
- filter must be a non-empty array of non-empty strings
- filter status_class values must be 2xx, 4xx, or 5xx
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/059e1192b251cc1e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/agent-mcp.ts:486
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");
}
}
}
function optionalEnum(args: JSONObject, key: string, values: string[]): void {
const value = args[key];
if (value !== undefined && (typeof value !== "string" || !values.includes(value))) {
throw new Error(`${key} must be one of ${values.join(", ")}`);
}View on GitHub (pinned to 3ee70a1026)