JuliusBrussee/caveman · warning
${key} must be one of ${values.join(", ")}
Error message
${key} must be one of ${values.join(", ")} What it means
optionalEnum() validates optional enumerated arguments on caveman_trace_search: date_field must be "occurred" or "updated", group_by must be "session", "workflow", "model", or "member" (and within sort, by must be timestamp/total_cost_usd/latency_ms/total_tokens and dir must be asc/desc). Any non-member string (or non-string value) throws with the key and the accepted list in the message.
Source
Thrown at packages/cli/src/agent-mcp.ts:503
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(", ")}`);
}
}
function validateTraceSearch(args: JSONObject): void {
validateTraceFilters(args);
for (const key of ["from", "to"]) {
const value = args[key];
if (value !== undefined && typeof value !== "string") throw new Error(`${key} must be a string`);
}
optionalEnum(args, "date_field", ["occurred", "updated"]);
optionalEnum(args, "group_by", ["session", "workflow", "model", "member"]);
const pageSize = args.page_size;
if (pageSize !== undefined && (!Number.isSafeInteger(pageSize) || (pageSize as number) < 1 || (pageSize as number) > 500)) {
throw new Error("page_size must be an integer from 1 to 500");
}
const sort = args.sort;
if (sort !== undefined) {
if (!sort || typeof sort !== "object" || Array.isArray(sort)) throw new Error("sort must be an object");View on GitHub (pinned to 27d5a3981a)
Solutions
- Read the accepted values straight from the error message and use one verbatim.
- Omit the argument when unsure — every optionalEnum argument is optional.
- Upgrade the caveman CLI if you expected a value (e.g. a new group_by member) that this version rejects.
Example fix
// before
{ date_field: "created", group_by: "trace" }
// after
{ date_field: "occurred", group_by: "session" } Defensive patterns
Strategy: validation
Validate before calling
function checkEnum(value: unknown, key: string, allowed: string[]): void {
if (value !== undefined && (typeof value !== "string" || !allowed.includes(value))) {
throw new Error(`${key} must be one of ${allowed.join(", ")}`);
}
}
checkEnum(args.date_field, "date_field", ["occurred", "updated"]);
checkEnum(args.group_by, "group_by", ["session", "workflow", "model", "member"]); Type guard
function isEnum<T extends string>(v: unknown, allowed: readonly T[]): v is T {
return typeof v === "string" && (allowed as readonly string[]).includes(v);
} Prevention
- Copy allowed values from the tool schema, not from memory.
- Treat every enum arg as optional; omit rather than guess.
When it happens
Trigger: date_field: "created"; group_by: "trace" or "agent"; sort.dir: "ascending"; a number or null where the enum is expected.
Common situations: Guessing plausible values not in the schema; version skew where an older CLI lacks a newer enum member; models free-typing the enum.
Related errors
- filters must be an object
- unknown trace filter(s): ${unknown.sort().join(", ")}
- filter monitor.verdict must be pass, fail, or error
- ${key} must be a string
- cave_budget_on_exhausted_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/9705716c1025b87d.
Report an issue: GitHub.