tinyhumansai/openhuman · error · SpecError
must be an array
Error message
must be an array
What it means
Thrown by validateSpec() in scripts/agent-batch/lib.mjs when an agent carries an allowed_shared_paths field that is not an array. allowed_shared_paths is the optional per-agent escape hatch that exempts specific paths from findOverlaps() collision detection (e.g. a shared coverage matrix), so it must be a list even when it names a single file.
Source
Thrown at scripts/agent-batch/lib.mjs:168
`${at}.owned_paths[${j}]`,
);
}
if (p.includes("*") || p.includes("?")) {
throw new SpecError(
`globs not allowed — use directory prefixes (got "${p}")`,
`${at}.owned_paths[${j}]`,
);
}
if (p.startsWith("/")) {
throw new SpecError(
`paths must be repo-relative, not absolute (got "${p}")`,
`${at}.owned_paths[${j}]`,
);
}
}
if ("allowed_shared_paths" in agent) {
if (!Array.isArray(agent.allowed_shared_paths)) {
throw new SpecError("must be an array", `${at}.allowed_shared_paths`);
}
}
if ("labels" in agent && !Array.isArray(agent.labels)) {
throw new SpecError("must be an array", `${at}.labels`);
}
}
return spec;
}
// Pure overlap detection: returns an array of collisions. Each entry is
// { a, b, pathA, pathB, reason } where reason is "prefix" (one contains the
// other) or "exact" (identical). Empty array = disjoint.
//
// Shared paths in allowed_shared_paths are NOT considered collisions — they
// are escape hatches for unavoidably-shared files like the coverage matrix.
export function findOverlaps(spec) {
const collisions = [];
for (let i = 0; i < spec.agents.length; i++) {View on GitHub (pinned to a221052e0d)
Solutions
- Wrap the value in an array: "allowed_shared_paths": ["docs/coverage-matrix.md"]
- If the field is not needed for this agent, delete it entirely — it is optional
- Re-run the agent-batch command; validation reports the exact agents[i] index in the error path
Example fix
// before "allowed_shared_paths": "docs/matrix.md" // after "allowed_shared_paths": ["docs/matrix.md"]
Defensive patterns
Strategy: validation
Validate before calling
const ok = spec.agents.every(
(a) => !("allowed_shared_paths" in a) || Array.isArray(a.allowed_shared_paths),
);
if (!ok) throw new Error("allowed_shared_paths must always be an array when present"); Type guard
function isPathList(v) {
return v === undefined || (Array.isArray(v) && v.every((p) => typeof p === "string" && p.length > 0));
} Prevention
- Normalize specs in CI: a lint step that coerces scalar strings to [string] or rejects them
- Remember both optional list fields (allowed_shared_paths, labels) share the same array rule — write them identically
When it happens
Trigger: A spec with "allowed_shared_paths": "docs/coverage-matrix.md" (a bare string) or an object/number at agents[i]. The field is only inspected when present ("allowed_shared_paths" in agent), so omitting it entirely never triggers this.
Common situations: Spec authors shorten a one-element list to a scalar out of habit, or YAML-to-JSON converters collapse a single-item list. Because the sibling owned_paths field is required and heavily validated, people assume the same string form is fine here too.
Related errors
- paths must be repo-relative, not absolute (got "${p}")
- Failed to parse service CLI output as JSON: parsed value doe
- ${label} must be a positive integer
- ${label} must be a positive integer
- ${label} must be a non-negative integer
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/a28ef0a7f21f8dd1.
Report an issue: GitHub.