JuliusBrussee/caveman · warning
filters must be an object
Error message
filters must be an object
What it means
validateTraceFilters() rejects a `filters` argument that is present but not a plain object: null, an array, a string, or a number all fail. `filters` must be a JSON object whose keys are recognized trace filter names; omitting it entirely is fine.
Source
Thrown at packages/cli/src/agent-mcp.ts:448
if (typeof candidate.status === "number") structuredContent.status = candidate.status;
return {
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
structuredContent,
isError: true,
};
}
async function withProjectQuery(client: AgentMcpClient, path: string): Promise<string> {
if (!PROJECT_QUERY_PATHS.has(path)) return path;
const projectId = await client.projectId();
const query = new URLSearchParams({ project_id: projectId });
return `${path}?${query}`;
}
function validateTraceFilters(args: JSONObject): void {
const filters = args.filters;
if (filters === undefined) return;
if (!filters || typeof filters !== "object" || Array.isArray(filters)) throw new Error("filters must be an object");
const unknown = Object.keys(filters).filter((key) => !TRACE_FILTER_KEYS.has(key));
if (unknown.length > 0) throw new Error(`unknown trace filter(s): ${unknown.sort().join(", ")}`);
const stringListKeys = [
"workflow",
"agent",
"model",
"provider",
"error_code",
"auth_mode",
"runtime_mode",
"cache_status",
"session_id",
"client_user_hash",
"trace_id",
"member_user_id",
"api_key_id",
"optimization_id",
"status_class",View on GitHub (pinned to 27d5a3981a)
Solutions
- Pass filters as a real JSON object: {"filters": {"model": ["gpt-4"]}}.
- Omit the filters key entirely when no filtering is needed.
- JSON.parse strings before embedding them in the tool args.
Example fix
// before
{ filters: JSON.stringify({ model: ["gpt-4"] }) }
// after
{ filters: { model: ["gpt-4"] } } Defensive patterns
Strategy: type-guard
Validate before calling
if (args.filters !== undefined) {
if (typeof args.filters !== "object" || args.filters === null || Array.isArray(args.filters)) {
throw new Error("filters must be a plain object");
}
} Type guard
function isPlainObject(v: unknown): v is Record<string, unknown> {
return typeof v === "object" && v !== null && !Array.isArray(v);
} Prevention
- Build filters objects in code, never from serialized strings.
- Omit filters rather than sending null when unneeded.
When it happens
Trigger: Passing filters as an array of pairs ([["model", [...]]]), a JSON string ('{"model":["gpt"]}'), or null in a caveman_trace_search call.
Common situations: A model double-serializing the filters object; clients building query-string-style arrays; treating filters as optional and sending null instead of omitting the key.
Related errors
- unknown trace filter(s): ${unknown.sort().join(", ")}
- filter ${key} must be a non-empty array of non-empty strings
- filter status_class values must be 2xx, 4xx, or 5xx
- filter ${key} must be a finite number
- filter ${key} must be a boolean
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/e5f3b2a5cffd6f73.
Report an issue: GitHub.