{"record":{"id":"059e1192b251cc1e","repo":"JuliusBrussee/caveman","slug":"filter-key-must-be-a-boolean","errorCode":null,"errorMessage":"filter ${key} must be a boolean","messagePattern":"filter (.+?) must be a boolean","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/cli/src/agent-mcp.ts","lineNumber":486,"sourceCode":"  for (const key of stringListKeys) {\n    const value = filters[key];\n    if (value === undefined) continue;\n    if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== \"string\" || entry.trim() === \"\")) {\n      throw new Error(`filter ${key} must be a non-empty array of non-empty strings`);\n    }\n    if (key === \"status_class\" && value.some((entry) => ![\"2xx\", \"4xx\", \"5xx\"].includes(entry as string))) {\n      throw new Error(\"filter status_class values must be 2xx, 4xx, or 5xx\");\n    }\n  }\n  for (const key of [\"min_cost_usd\", \"max_cost_usd\", \"min_total_tokens\", \"max_total_tokens\", \"min_latency_ms\", \"max_latency_ms\"]) {\n    const value = filters[key];\n    if (value !== undefined && (typeof value !== \"number\" || !Number.isFinite(value))) {\n      throw new Error(`filter ${key} must be a finite number`);\n    }\n  }\n  for (const key of [\"has_error\", \"compressed\"]) {\n    const value = filters[key];\n    if (value !== undefined && typeof value !== \"boolean\") throw new Error(`filter ${key} must be a boolean`);\n  }\n  const monitor = filters.monitor;\n  if (monitor !== undefined) {\n    if (!monitor || typeof monitor !== \"object\" || Array.isArray(monitor)) throw new Error(\"filter monitor must be an object\");\n    const monitorUnknown = Object.keys(monitor).filter((key) => key !== \"id\" && key !== \"verdict\");\n    if (monitorUnknown.length > 0) throw new Error(`filter monitor has unknown key(s): ${monitorUnknown.sort().join(\", \")}`);\n    if (typeof monitor.id !== \"string\" || monitor.id.trim() === \"\") throw new Error(\"filter monitor.id is required\");\n    if (typeof monitor.verdict !== \"string\" || ![\"pass\", \"fail\", \"error\"].includes(monitor.verdict)) {\n      throw new Error(\"filter monitor.verdict must be pass, fail, or error\");\n    }\n  }\n}\n\nfunction optionalEnum(args: JSONObject, key: string, values: string[]): void {\n  const value = args[key];\n  if (value !== undefined && (typeof value !== \"string\" || !values.includes(value))) {\n    throw new Error(`${key} must be one of ${values.join(\", \")}`);\n  }","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/agent-mcp.ts#L468-L504","documentation":"The boolean filters has_error and compressed must be actual JSON booleans when present. Strings (\"true\"), 0/1, or null throw with the key named. Omitting the key is valid.","triggerScenarios":"has_error: \"true\" (string from env var or query param); has_error: 1; compressed: \"false\" which would otherwise be truthy and silently wrong.","commonSituations":"Reading flags from process.env or URL query strings and passing them through unconverted; LLM tool calls quoting booleans.","solutions":["Convert before calling: value === \"true\" / Boolean(value) as appropriate for the source.","Send real JSON true/false literals.","Omit the key when the filter is not wanted."],"exampleFix":"// before\n{ filters: { has_error: process.env.HAS_ERROR } } // string \"true\"/undefined\n\n// after\n{ filters: { has_error: process.env.HAS_ERROR === \"1\" } }","handlingStrategy":"type-guard","validationCode":"for (const k of [\"has_error\", \"compressed\"]) {\n  if (filters[k] !== undefined && typeof filters[k] !== \"boolean\") {\n    throw new Error(`${k} must be boolean`);\n  }\n}","typeGuard":"function isBoolean(v: unknown): v is boolean { return typeof v === \"boolean\"; }","tryCatchPattern":null,"preventionTips":["Convert env/query-string flags with === comparisons, not truthiness.","Omit boolean filters rather than sending null."],"tags":["mcp","validation","filters","booleans"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}