tinyhumansai/openhuman · error · SpecError
paths must be repo-relative, not absolute (got "${p}")
Error message
paths must be repo-relative, not absolute (got "${p}") What it means
Thrown by validateSpec() in scripts/agent-batch/lib.mjs while validating an agent-batch spec. Each agents[].owned_paths entry must be a repo-relative directory prefix; an entry starting with '/' is rejected because ownership tracking and the findOverlaps() collision check operate on paths relative to the repo root, where an absolute path would never match and would silently break disjointness guarantees.
Source
Thrown at scripts/agent-batch/lib.mjs:160
`${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) {
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 isView on GitHub (pinned to a221052e0d)
Solutions
- Strip the repo-root prefix from the entry so it is relative, e.g. "/home/me/openhuman/src/agent" → "src/agent"
- If you generated the spec programmatically, re-generate it with paths relative to the repo root (path.relative(repoRoot, p)) and re-run
- Confirm no other owned_paths entries have the same problem — validation stops at the first offender, so fix and re-run until the spec passes
Example fix
// spec.json — before "owned_paths": ["/home/me/openhuman/src/agent"] // after "owned_paths": ["src/agent"]
Defensive patterns
Strategy: validation
Validate before calling
// Run before handing the spec to any agent-batch command
import { readFileSync } from "node:fs";
const spec = JSON.parse(readFileSync("batch.json", "utf8"));
for (const [i, agent] of spec.agents.entries()) {
for (const [j, p] of agent.owned_paths.entries()) {
if (typeof p !== "string" || p.length === 0) throw new Error(`agents[${i}].owned_paths[${j}]: empty`);
if (p.startsWith("/")) throw new Error(`agents[${i}].owned_paths[${j}]: absolute path ${p}`);
}
} Type guard
function isRepoRelativePath(p) {
return typeof p === "string" && p.length > 0 && !p.includes("*") && !p.includes("?") && !p.startsWith("/");
} Try / catch
try {
validateSpec(spec);
} catch (e) {
if (e instanceof SpecError) {
console.error(`spec invalid at ${e.path}: ${e.message}`);
process.exit(2);
}
throw e;
} Prevention
- Generate owned_paths with path.relative(repoRoot, absPath) instead of hand-typing them
- Treat the SpecError.path field as the address to fix — it names the exact agents[i].owned_paths[j] slot
- Keep a known-good spec as a template and diff new specs against it
When it happens
Trigger: A spec JSON where any agents[i].owned_paths[j] string starts with '/', e.g. "/home/user/openhuman/src/agent" or "/Users/me/repo/docs". validateSpec() is called by every agent-batch subcommand (launch/status) right after loadSpec(), so the very first run against such a spec fails at agents[i].owned_paths[j] with the offending path echoed.
Common situations: Authors generate the spec from shell output ($PWD-prefixed paths), paste paths from an editor's 'copy absolute path' action, or port a spec from a machine-specific CI layout. The check sits directly after the glob check, so 'src/*' fails first with a different message; only clean-but-absolute paths reach this throw.
Related errors
- must be an array
- 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/b8d73fbc03b56574.
Report an issue: GitHub.