tinyhumansai/openhuman · error · SpecError

owned_paths must be a non-empty array

Error message

owned_paths must be a non-empty array

What it means

agent.owned_paths must be a non-empty Array — these are the directory prefixes the agent is allowed to write, and the input to findOverlaps() for disjointness checking downstream. An agent owning nothing is meaningless, so empty arrays (or non-arrays) are rejected before element validation. Path is "agents[i].owned_paths".

Source

Thrown at scripts/agent-batch/lib.mjs:140

    }
    if (m[1] !== agent.id) {
      throw new SpecError(
        `branch id segment "${m[1]}" does not match agent id "${agent.id}"`,
        `${at}.branch`,
      );
    }
    if (Number(m[2]) !== agent.issue) {
      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}]`,
        );
      }

View on GitHub (pinned to a221052e0d)

Solutions

  1. List at least one repo-relative directory prefix covering the agent's changes, e.g. ["scripts/ci/"]
  2. Wrap single paths in an array: "src/" → ["src/"]
  3. If unsure of scope, give the owning domain directory (one of src/openhuman/<domain>/)

Example fix

// before
"owned_paths": []

// after
"owned_paths": ["scripts/ci/", ".github/workflows/"]
Defensive patterns

Strategy: validation

Validate before calling

for (const [i, a] of spec.agents.entries()) {
  if (!Array.isArray(a.owned_paths) || a.owned_paths.length === 0) {
    console.error(`agents[${i}].owned_paths must be a non-empty array`);
    process.exit(1);
  }
}

Type guard

/** @param {unknown} v */
function isNonEmptyStringArray(v) {
  return Array.isArray(v) && v.length > 0 && v.every((p) => typeof p === "string" && p.length > 0);
}

Try / catch

try {
  validateSpec(spec);
} catch (e) {
  if (e instanceof SpecError && e.path?.endsWith(".owned_paths")) {
    console.error(`scope the agent to at least one directory prefix: ${e.message}`);
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: "owned_paths": [], "owned_paths": "src/", "owned_paths": {"src": true}, or null on an agent entry.

Common situations: Omitting scope decisions until later and leaving an empty list; putting a single string instead of a one-element array; generator defaulting to [] when it could not map the work to paths.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/25f9907d3e496957. Report an issue: GitHub.