tinyhumansai/openhuman · error · SpecError
must be a non-empty string
Error message
must be a non-empty string
What it means
Each element of agent.owned_paths must be a string of length > 0 — checked inside the per-path loop with index-precise path "agents[i].owned_paths[j]". This is purely type/emptiness; format policy (no globs, not absolute) is enforced by the following checks. Note it checks length only, so a whitespace-only path passes here.
Source
Thrown at scripts/agent-batch/lib.mjs:148
throw new SpecError(
`branch issue segment "${m[2]}" does not match agent issue ${agent.issue}`,
`${at}.branch`,
);
}
if (seenBranch.has(agent.branch)) {
throw new SpecError(`duplicate branch "${agent.branch}"`, `${at}.branch`);
}
seenBranch.add(agent.branch);
if (!Array.isArray(agent.owned_paths) || agent.owned_paths.length === 0) {
throw new SpecError(
"owned_paths must be a non-empty array",
`${at}.owned_paths`,
);
}
for (let j = 0; j < agent.owned_paths.length; j++) {
const p = agent.owned_paths[j];
if (typeof p !== "string" || p.length === 0) {
throw new SpecError(
"must be a non-empty string",
`${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) {View on GitHub (pinned to a221052e0d)
Solutions
- Remove the empty entry at the reported index (e.g. agents[1].owned_paths[2])
- Sanitize before validating: owned_paths = owned_paths.filter(p => typeof p === "string" && p.length > 0)
- Fix the generator so joins/splits do not emit empty elements
Example fix
// before "owned_paths": ["src/openhuman/meet/", ""] // after "owned_paths": ["src/openhuman/meet/"]
Defensive patterns
Strategy: validation
Validate before calling
for (const [i, a] of spec.agents.entries()) {
a.owned_paths = a.owned_paths.filter((p) => typeof p === "string" && p.length > 0);
if (a.owned_paths.length === 0) { /* now error 197 semantics */ }
} Type guard
/** @param {unknown} v */
function isNonEmptyString(v) {
return typeof v === "string" && v.length > 0;
} Try / catch
try {
validateSpec(spec);
} catch (e) {
if (e instanceof SpecError && e.path?.includes(".owned_paths[")) {
const idx = /owned_paths\[(\d+)]/.exec(e.path ?? "")[1];
console.error(`remove/fix the empty entry at ${e.path}`);
process.exit(1);
}
throw e;
} Prevention
- Filter empty strings out of generated path lists before serializing the spec
- Avoid split("\n") on path lists without a trailing filter for empty lines
When it happens
Trigger: owned_paths containing "" (empty string, often from a trailing comma in a generator join), null, a number, or undefined holes in a sparse array.
Common situations: Generating paths with split(" ") or filter steps that leave empty strings; JSON arrays with explicit null entries; trailing separators producing one empty final element.
Related errors
- owned_paths must be a non-empty array
- globs not allowed — use directory prefixes (got "${p}")
- batch_id must be a kebab-case slug
- base_repo must be "tinyhumansai/openhuman" (got "${spec.base
- base_branch must be "main" (got "${spec.base_branch}")
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/90ec879630d34b92.
Report an issue: GitHub.