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

  1. Remove the empty entry at the reported index (e.g. agents[1].owned_paths[2])
  2. Sanitize before validating: owned_paths = owned_paths.filter(p => typeof p === "string" && p.length > 0)
  3. 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

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


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