JuliusBrussee/caveman · error
${field} is not an array (got ${typeof value})
Error message
${field} is not an array (got ${typeof value}) What it means
Thrown by expectArray() in the subagent request analyzer when a field it expects to be an array (e.g. tools, messages) is present but has a non-array type. The library deliberately fails loudly instead of coercing: an unexpectedly-shaped field must be reported as unparsed, because silently counting it as zero would publish a false measurement (e.g. "0 tools" that looks like a real result).
Source
Thrown at packages/subagent-tax/lib/analyze.mjs:20
// prints. All sizes are JSON-serialized character counts of what the harness
// actually sent — nothing is inferred here except the chars themselves.
const LLM_KINDS = new Set([
"anthropic-messages",
"openai-chat",
"openai-responses",
"gemini-generatecontent",
]);
const jsonChars = (value) => (value === undefined || value === null ? 0 : JSON.stringify(value).length);
const isSystemRole = (m) => m && (m.role === "system" || m.role === "developer");
// A field present in an unexpected shape is reported as unparsed, never
// silently counted as zero — a false "0 tools" reads as a real measurement.
function expectArray(value, field) {
if (value === undefined || value === null) return [];
if (!Array.isArray(value)) throw new Error(`${field} is not an array (got ${typeof value})`);
return value;
}
function anthropicParts(body) {
const tools = expectArray(body.tools, "tools").map((t) => ({ name: t?.name ?? t?.type ?? "?", chars: jsonChars(t) }));
// The fixed instruction payload arrives as `system` AND, in some harnesses,
// as system-role entries inside `messages` — count both or the flagship row
// under-reports its own prefix.
const messages = expectArray(body.messages, "messages");
const sysMessages = messages.filter(isSystemRole);
const rest = messages.filter((m) => !isSystemRole(m));
return {
system_chars: jsonChars(body.system) + (sysMessages.length ? jsonChars(sysMessages) : 0),
tools,
messages_chars: jsonChars(rest.length ? rest : undefined),
};
}
View on GitHub (pinned to 27d5a3981a)
Solutions
- Inspect the offending request body (the error names the field and its typeof) and fix the producer so the field is a real array.
- If the input is a corrupted log line, re-capture or repair the fixture before re-running the analyzer.
- If you are adding support for a new harness shape, normalize the body to the provider's documented array shape before passing it to the analyzer — do not change expectArray to coerce.
Example fix
// before
const body = { tools: { name: "bash" }, messages: [] };
const parts = anthropicParts(body); // throws: tools is not an array (got object)
// after
const body = { tools: [{ name: "bash" }], messages: [] };
const parts = anthropicParts(body); Defensive patterns
Strategy: validation
Validate before calling
function hasArrayFields(body, fields) {
return fields.every((f) => body[f] === undefined || body[f] === null || Array.isArray(body[f]));
}
if (!hasArrayFields(body, ["tools", "messages", "system"])) {
// route to an 'unparsed' bucket instead of calling the analyzer
} Type guard
const isMessageArray = (v) => Array.isArray(v) && v.every((m) => m && typeof m.role === "string");
Try / catch
try {
const parts = anthropicParts(body);
} catch (err) {
if (err instanceof Error && / is not an array \(got /.test(err.message)) {
recordUnparsed(body); // never treat as zero — mark unparsed
} else throw err;
} Prevention
- Validate captured request bodies against the provider's documented schema before analysis.
- Keep a corpus of known-good fixture bodies in tests so shape regressions surface there first.
When it happens
Trigger: Calling the analyzer (anthropicParts or the equivalent openai/gemini body parsers) with a captured request body where body.tools is a string, an object, or a number — for example a harness that sends tools as a single object instead of a one-element array, or messages as an object map keyed by role.
Common situations: Analyzing logs from a new or custom agent harness whose request shape drifted from the provider API; a partial/corrupted JSON line where the field parsed to a scalar; a schema change by the provider (e.g. tools becoming an object with a "definitions" wrapper).
Related errors
- cave_tool_input_schema_mismatch:${options.name}
- caveman agent: tool Standard Schema must implement version 1
- option not found
- cave_harness_adapter_version_invalid
- cave_harness_upstream_version_mismatch
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/9bbbc89f8748c2a4.
Report an issue: GitHub.