{"record":{"id":"9705716c1025b87d","repo":"JuliusBrussee/caveman","slug":"key-must-be-one-of-values-join","errorCode":null,"errorMessage":"${key} must be one of ${values.join(\", \")}","messagePattern":"(.+?) must be one of (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/agent-mcp.ts","lineNumber":503,"sourceCode":"    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\"]);\n  optionalEnum(args, \"group_by\", [\"session\", \"workflow\", \"model\", \"member\"]);\n  const pageSize = args.page_size;\n  if (pageSize !== undefined && (!Number.isSafeInteger(pageSize) || (pageSize as number) < 1 || (pageSize as number) > 500)) {\n    throw new Error(\"page_size must be an integer from 1 to 500\");\n  }\n  const sort = args.sort;\n  if (sort !== undefined) {\n    if (!sort || typeof sort !== \"object\" || Array.isArray(sort)) throw new Error(\"sort must be an object\");","sourceCodeStart":485,"sourceCodeEnd":521,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/agent-mcp.ts#L485-L521","documentation":"optionalEnum validates that an optional top-level argument is either omitted or a string from a fixed set. validateTraceSearch uses it for `date_field` (occurred|updated) and `group_by` (session|workflow|model|member). Passing a non-string or an out-of-set value throws this error naming the key and the allowed values.","triggerScenarios":"trace_search with {\"date_field\":\"created\"} (not allowed), {\"group_by\":\"agent\"} (invalid), {\"group_by\":123} (non-string), or {\"date_field\":null} treated as a defined non-string value only if not undefined.","commonSituations":"Guessing enum values instead of reading the tool schema; mixing up date_field options with other APIs' field names (e.g. \"created_at\"); group_by values copied from a different reporting endpoint.","solutions":["Use exactly one of the allowed values shown in the message: date_field = occurred|updated, group_by = session|workflow|model|member.","Remove the argument entirely if you don't need it (both are optional).","Fix casing — values are lowercase and case-sensitive.","Validate against the tool's input schema before sending."],"exampleFix":"// before\n{ \"group_by\": \"agent\" }\n// after\n{ \"group_by\": \"model\" }","handlingStrategy":"validation","validationCode":"const DATE_FIELDS = [\"occurred\", \"updated\"];\nconst GROUP_BYS = [\"session\", \"workflow\", \"model\", \"member\"];\nif (args.date_field !== undefined && !DATE_FIELDS.includes(args.date_field))\n  throw new Error(`date_field must be one of ${DATE_FIELDS.join(\", \")}`);\nif (args.group_by !== undefined && !GROUP_BYS.includes(args.group_by))\n  throw new Error(`group_by must be one of ${GROUP_BYS.join(\", \")}`);","typeGuard":"function isOptionalEnum(v, values) {\n  return v === undefined || (typeof v === \"string\" && values.includes(v));\n}","tryCatchPattern":"try {\n  await traceSearch(args);\n} catch (e) {\n  const m = e.message.match(/^(\\w+) must be one of (.+)$/);\n  if (m) throw new Error(`Fix ${m[1]}: allowed values are ${m[2]}`);\n  throw e;\n}","preventionTips":["Keep the allowed enum lists in shared constants next to the call site.","Only set the argument when you have a valid value (they are optional).","Validate option values at config-load time, not request time."],"tags":["validation","enum","mcp","arguments"],"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"}