tinyhumansai/openhuman · error · SpecError
id must match /^a\\d{2,3}$/ (got "${agent.id}")
Error message
id must match /^a\\d{2,3}$/ (got "${agent.id}") What it means
agent.id must be a string matching /^a\d{2,3}$/ — the literal letter 'a' followed by exactly 2 or 3 digits ("a01" through "a999"). The id encodes agent ordering and appears in branch names (enforced later by BRANCH_RE), so the format is strict. The offending value is shown in the message with path "agents[i].id".
Source
Thrown at scripts/agent-batch/lib.mjs:98
"agents",
);
}
const seenId = new Set();
const seenIssue = new Set();
const seenBranch = new Set();
for (let i = 0; i < spec.agents.length; i++) {
const agent = spec.agents[i];
const at = `agents[${i}]`;
if (!agent || typeof agent !== "object" || Array.isArray(agent)) {
throw new SpecError("must be an object", at);
}
for (const key of REQUIRED_AGENT) {
if (!(key in agent))
throw new SpecError(`missing required field "${key}"`, at);
}
if (typeof agent.id !== "string" || !/^a\d{2,3}$/.test(agent.id)) {
throw new SpecError(
`id must match /^a\\d{2,3}$/ (got "${agent.id}")`,
`${at}.id`,
);
}
if (seenId.has(agent.id))
throw new SpecError(`duplicate id "${agent.id}"`, `${at}.id`);
seenId.add(agent.id);
if (!Number.isInteger(agent.issue) || agent.issue <= 0) {
throw new SpecError("issue must be a positive integer", `${at}.issue`);
}
if (seenIssue.has(agent.issue)) {
throw new SpecError(`duplicate issue #${agent.issue}`, `${at}.issue`);
}
seenIssue.add(agent.issue);
if (typeof agent.title !== "string" || agent.title.trim().length === 0) {
throw new SpecError("title must be a non-empty string", `${at}.title`);
}
const m = BRANCH_RE.exec(agent.branch);View on GitHub (pinned to a221052e0d)
Solutions
- Zero-pad to two digits: a1 → a01 (three digits a100+ also valid)
- Keep it lowercase with no prefix/suffix beyond the digits
- If renumbering, also update the branch's id segment to match (error 194 will otherwise fire next)
Example fix
// before
{ "id": "a1", "branch": "cursor/a1-5312-fix-ci" }
// after
{ "id": "a01", "branch": "cursor/a01-5312-fix-ci" } Defensive patterns
Strategy: validation
Validate before calling
for (const [i, a] of spec.agents.entries()) {
if (typeof a.id !== "string" || !/^a\d{2,3}$/.test(a.id)) {
console.error(`agents[${i}].id must match /^a\\d{2,3}$/ (got ${JSON.stringify(a.id)})`);
process.exit(1);
}
} Type guard
/** @param {unknown} v */
function isAgentId(v) {
return typeof v === "string" && /^a\d{2,3}$/.test(v);
} Try / catch
try {
validateSpec(spec);
} catch (e) {
if (e instanceof SpecError && e.path?.endsWith(".id")) {
console.error(`agent id format bad: ${e.message}`);
process.exit(1);
}
throw e;
} Prevention
- Zero-pad ids to two digits from the start (a01, a02, ...)
- Generate ids programmatically: `a${String(i + 1).padStart(2, "0")}`
- Remember the same id appears in the branch name — change both together
When it happens
Trigger: "id": "a1" (one digit), "a1234" (four digits), "A01" (uppercase), "agent01", "01", or a non-string id like 1.
Common situations: Numbering agents from 1 without zero-padding ("a1"); exceeding 999 agents in numbering scheme; auto-uppercasing editors; using "agent01" style from a different convention.
Related errors
- batch_id must be a kebab-case slug
- branch must match cursor/<id>-<issue>-<slug> (got "${agent.b
- base_repo must be "tinyhumansai/openhuman" (got "${spec.base
- base_branch must be "main" (got "${spec.base_branch}")
- tracking_issue must be a positive integer
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/d6fa1a2f0ba0d693.
Report an issue: GitHub.