JuliusBrussee/caveman · error
filters must be an object
Error message
filters must be an object
What it means
validateTraceFilters checks the optional filters argument of trace search tools. If filters is provided it must be a plain (non-null, non-array) object; anything else — null, a scalar, or an array — throws "filters must be an object" before any further filter-key validation runs.
Solutions
- Pass filters as a plain object keyed by filter name
- Convert array-of-pairs input into an object before calling
- Omit filters entirely (or pass undefined) when there are no filters
Example fix
// before
searchTraces({ filters: [{ key: 'workflow', value: 'deploy' }] });
// after
searchTraces({ filters: { workflow: ['deploy'] } }); Defensive patterns
Strategy: type-guard
Validate before calling
function assertFiltersObject(filters) {
if (filters === undefined) return;
if (filters === null || typeof filters !== 'object' || Array.isArray(filters)) {
throw new Error('filters must be a plain object');
}
}
assertFiltersObject(args.filters); Type guard
function isPlainObject(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try {
await searchTraces({ filters });
} catch (error) {
if (error.message === 'filters must be an object') {
filters = Object.fromEntries(filters.map((f) => [f.key, f.value]));
}
} Prevention
- Model filters as a keyed object, never an array of pairs
- Type filters as Record<string, unknown> in client code
- Validate filter input shape before the tool call
- Normalize query-string filters into objects at the boundary
When it happens
Trigger: Passing filters: null, filters: [], filters: "workflow=foo", or filters: 42 to the trace search tool; arrays are explicitly rejected even though they pass a naive typeof check.
Common situations: Serializing filters from a query string into an array; JSON schemas allowing any type so the model sends an array of {key,value} pairs; frontends building filters as a list of conditions.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- filter must be a boolean
- filter monitor must be an object
- filter must be a finite number
- filter must be a non-empty array of non-empty strings
- filter status_class values must be 2xx, 4xx, or 5xx
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e5f3b2a5cffd6f73.
Report an issue: GitHub.
Appendix: 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 3ee70a1026)