JuliusBrussee/caveman · error
sort must be an object
Error message
sort must be an object
What it means
The optional `sort` argument of trace_search must be a plain object with at most `by` and `dir` keys. If sort is provided but is not an object (number, string, boolean, or null) or is an array, this error is thrown before any key checks.
Solutions
- Wrap the sort spec in an object: {"sort":{"by":"timestamp","dir":"desc"}}.
- Don't send null — omit the key entirely when not sorting.
- Convert array/string sort forms into the object form.
- Ensure the object has only `by` and `dir` keys (see the unknown-keys error).
Example fix
// before
{ "sort": "timestamp:desc" }
// after
{ "sort": { "by": "timestamp", "dir": "desc" } } Defensive patterns
Strategy: type-guard
Validate before calling
if (args.sort !== undefined && (typeof args.sort !== "object" || args.sort === null || Array.isArray(args.sort)))
throw new Error("sort must be an object like {by, dir}"); Type guard
function isPlainObject(v) {
return typeof v === "object" && v !== null && !Array.isArray(v);
} Try / catch
try {
await traceSearch(args);
} catch (e) {
if (e.message === "sort must be an object") {
throw new Error("Use sort: { by: 'timestamp', dir: 'desc' } — string/array sort is not supported");
}
throw e;
} Prevention
- Always build sort as {by, dir}; never send shorthand strings or arrays.
- Omit sort (don't send null) when no ordering is needed.
- Centralize sort construction in one helper.
When it happens
Trigger: trace_search with {"sort":"timestamp"} (string instead of object), {"sort":["timestamp"]} (array), {"sort":null} (non-undefined null), or {"sort":true}.
Common situations: Shorthand sort strings copied from REST APIs that accept "field:dir"; arrays of sort clauses from Elasticsearch-style clients; JSON configs where sort was a string; null sent explicitly by serializers.
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
- cursor must be an object
- must be a string
- sort has unknown key(s)
- cursor has unknown key(s)
- cursor. must be a string
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/8a35841fa78fa7ba.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/agent-mcp.ts:521
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");
const unknown = Object.keys(sort).filter((key) => key !== "by" && key !== "dir");
if (unknown.length > 0) throw new Error(`sort has unknown key(s): ${unknown.sort().join(", ")}`);
optionalEnum(sort, "by", ["timestamp", "total_cost_usd", "latency_ms", "total_tokens"]);
optionalEnum(sort, "dir", ["asc", "desc"]);
}
const cursor = args.cursor;
if (cursor !== undefined) {
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) throw new Error("cursor must be an object");
const unknown = Object.keys(cursor).filter((key) => key !== "sort_value" && key !== "request_id" && key !== "group_key");
if (unknown.length > 0) throw new Error(`cursor has unknown key(s): ${unknown.sort().join(", ")}`);
if (typeof cursor.sort_value !== "string" || cursor.sort_value === "") throw new Error("cursor.sort_value is required");
for (const key of ["request_id", "group_key"]) {
if (cursor[key] !== undefined && typeof cursor[key] !== "string") throw new Error(`cursor.${key} must be a string`);
}
}
}
async function callTool(client: AgentMcpClient, name: string, rawArgs: unknown): Promise<ToolResult> {View on GitHub (pinned to 3ee70a1026)