tinyhumansai/openhuman · error · SpecError

globs not allowed — use directory prefixes (got "${p}")

Error message

globs not allowed — use directory prefixes (got "${p}")

What it means

owned_paths entries must not contain the glob characters * or ? — the error text says "use directory prefixes". The reason is architectural: findOverlaps() enforces disjoint ownership via plain string prefix containment (comparePaths normalizes trailing slashes and checks startsWith), which cannot reason about glob semantics. A glob would silently defeat the overlap detector, so it is banned up front; the offending path is shown with index-precise path.

Source

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

      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) {
      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`);

View on GitHub (pinned to a221052e0d)

Solutions

  1. Replace globs with the enclosing directory prefix: "src/**/*.rs" → "src/" or a narrower "src/openhuman/web3/"
  2. Own whole directories even if the agent touches only some files — overlap rules compare prefixes, so pick the deepest directory that covers the work
  3. For a single file, use the file path itself ("app/src/App.tsx") — file paths have no glob chars

Example fix

// before
"owned_paths": ["src/openhuman/**/*.rs"]

// after
"owned_paths": ["src/openhuman/web3/"]
Defensive patterns

Strategy: validation

Validate before calling

for (const [i, a] of spec.agents.entries()) {
  for (const [j, p] of a.owned_paths.entries()) {
    if (typeof p === "string" && (p.includes("*") || p.includes("?"))) {
      console.error(`agents[${i}].owned_paths[${j}] uses a glob — replace with a directory prefix`);
      process.exit(1);
    }
  }
}

Try / catch

try {
  validateSpec(spec);
} catch (e) {
  if (e instanceof SpecError && /globs not allowed/.test(e.message)) {
    console.error(`rewrite as a directory prefix (e.g. "src/openhuman/web3/"): ${e.message}`);
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: "owned_paths": ["src/**/*.rs"], ["app/src/*"], or ["docs?.md"] on any agent. Any occurrence of * or ? anywhere in the path string triggers it.

Common situations: Porting file-scopes from .gitignore or CODEOWNERS syntax, which is glob-based; trying to express "all Rust files" instead of owning the directories; copy-pasting glob patterns from CI path filters.

Related errors


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