{"record":{"id":"479a8909ffb04a90","repo":"tinyhumansai/openhuman","slug":"agents-must-be-a-non-empty-array","errorCode":null,"errorMessage":"agents must be a non-empty array","messagePattern":"agents must be a non-empty array","errorType":"validation","errorClass":"SpecError","httpStatus":null,"severity":"error","filePath":"scripts/agent-batch/lib.mjs","lineNumber":75,"sourceCode":"    throw new SpecError(\n      `base_repo must be \"tinyhumansai/openhuman\" (got \"${spec.base_repo}\")`,\n      \"base_repo\",\n    );\n  }\n  if (spec.base_branch !== \"main\") {\n    throw new SpecError(\n      `base_branch must be \"main\" (got \"${spec.base_branch}\")`,\n      \"base_branch\",\n    );\n  }\n  if (!Number.isInteger(spec.tracking_issue) || spec.tracking_issue <= 0) {\n    throw new SpecError(\n      \"tracking_issue must be a positive integer\",\n      \"tracking_issue\",\n    );\n  }\n  if (!Array.isArray(spec.agents) || spec.agents.length === 0) {\n    throw new SpecError(\"agents must be a non-empty array\", \"agents\");\n  }\n  if (spec.agents.length > 25) {\n    throw new SpecError(\n      `batch size ${spec.agents.length} exceeds hard cap of 25`,\n      \"agents\",\n    );\n  }\n\n  const seenId = new Set();\n  const seenIssue = new Set();\n  const seenBranch = new Set();\n  for (let i = 0; i < spec.agents.length; i++) {\n    const agent = spec.agents[i];\n    const at = `agents[${i}]`;\n    if (!agent || typeof agent !== \"object\" || Array.isArray(agent)) {\n      throw new SpecError(\"must be an object\", at);\n    }\n    for (const key of REQUIRED_AGENT) {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/agent-batch/lib.mjs#L57-L93","documentation":"The top-level agents field must be a non-empty Array — the batch must contain at least one agent entry to be meaningful. This fires before any per-agent validation, so an empty or malformed agents list is reported before confusing downstream errors. The path tag is \"agents\".","triggerScenarios":"\"agents\": [], \"agents\": {} (object, not array), \"agents\": null, or agents omitted-but-null after the REQUIRED_TOP check passed with the key present holding a non-array.","commonSituations":"Starting a spec from a skeleton where agents was left empty to fill in later; a generator bug emitting an object keyed by agent id instead of an array; JSON merge tools dropping array contents.","solutions":["Add at least one valid agent object {id, issue, title, branch, owned_paths}","Ensure agents is a JSON array, not an object map","If you meant to validate a spec skeleton, finish populating it first — validateSpec has no draft mode"],"exampleFix":"// before\n\"agents\": []\n\n// after\n\"agents\": [\n  { \"id\": \"a01\", \"issue\": 5312, \"title\": \"Fix CI timeout\", \"branch\": \"cursor/a01-5312-fix-ci-timeout\", \"owned_paths\": [\"scripts/ci/\"] }\n]","handlingStrategy":"validation","validationCode":"if (!Array.isArray(spec.agents) || spec.agents.length === 0) {\n  console.error(\"agents must be a non-empty array\");\n  process.exit(1);\n}","typeGuard":"/** @param {unknown} v */\nfunction isNonEmptyArray(v) {\n  return Array.isArray(v) && v.length > 0;\n}","tryCatchPattern":"try {\n  validateSpec(spec);\n} catch (e) {\n  if (e instanceof SpecError && e.path === \"agents\") {\n    console.error(e.message);\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Validate the skeleton early in authoring, not just before launch","When generating agents from a work list, assert the list is non-empty before emitting the spec"],"tags":["validation","json","spec","agent-batch"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}