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

  1. Pass filters as a real JSON object: {"filters": {"model": ["gpt-4"]}}.
  2. Omit the filters key entirely when no filtering is needed.
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/e5f3b2a5cffd6f73. Report an issue: GitHub.