{"record":{"id":"9dc9d92d3cf7e227","repo":"JuliusBrussee/caveman","slug":"filter-monitor-verdict-must-be-pass-fail-or-erro","errorCode":null,"errorMessage":"filter monitor.verdict must be pass, fail, or error","messagePattern":"filter monitor\\.verdict must be pass, fail, or error","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/agent-mcp.ts","lineNumber":495,"sourceCode":"  }\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  }\n}\n\nfunction validateTraceSearch(args: JSONObject): void {\n  validateTraceFilters(args);\n  for (const key of [\"from\", \"to\"]) {\n    const value = args[key];\n    if (value !== undefined && typeof value !== \"string\") throw new Error(`${key} must be a string`);\n  }\n  optionalEnum(args, \"date_field\", [\"occurred\", \"updated\"]);","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/agent-mcp.ts#L477-L513","documentation":"A `monitor` filter present in trace_search must carry `verdict` as one of the exact strings \"pass\", \"fail\", or \"error\". Any other string, a non-string, or a missing verdict throws this error listing the allowed values.","triggerScenarios":"Calling trace_search with {\"filter\":{\"monitor\":{\"id\":\"m_1\",\"verdict\":\"passed\"}}} (wrong spelling), {\"verdict\":null}, {\"verdict\":\"PASS\"} (case-sensitive), or omitting verdict entirely while supplying id.","commonSituations":"Case sensitivity mistakes (\"Pass\"); using synonyms like \"success\"/\"failed\"; older payloads using different verdict vocabularies; UI sending a localized label instead of the enum value.","solutions":["Set monitor.verdict to exactly one of \"pass\", \"fail\", or \"error\" (lowercase).","Normalize/toLowerCase and map synonyms (success->pass, failure->fail) before the call.","Omit the monitor filter if you don't need verdict filtering rather than sending a partial monitor object.","Match the enum against the tool schema at build time to catch drift."],"exampleFix":"// before\n{ \"filter\": { \"monitor\": { \"id\": \"m_1\", \"verdict\": \"Passed\" } } }\n// after\n{ \"filter\": { \"monitor\": { \"id\": \"m_1\", \"verdict\": \"pass\" } } }","handlingStrategy":"validation","validationCode":"const VERDICTS = [\"pass\", \"fail\", \"error\"];\nif (filter.monitor && !VERDICTS.includes(filter.monitor.verdict))\n  throw new Error(`monitor.verdict must be one of ${VERDICTS.join(\", \")}`);","typeGuard":"function isMonitorVerdict(v) {\n  return v === \"pass\" || v === \"fail\" || v === \"error\";\n}","tryCatchPattern":"try {\n  await traceSearch(args);\n} catch (e) {\n  if (e.message.includes(\"monitor.verdict must be pass, fail, or error\")) {\n    args.filter.monitor.verdict = String(args.filter.monitor.verdict).toLowerCase();\n    return traceSearch(args);\n  }\n  throw e;\n}","preventionTips":["Use a const enum/union type for verdict values in client code.","Normalize casing and map synonyms before sending.","Copy enum values from the tool schema, not from UI labels."],"tags":["validation","enum","mcp","filter"],"backgroundTag":"invalid-enum-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}