{"record":{"id":"623a2a4c7f9baba0","repo":"nexu-io/open-design","slug":"invalid-imagegen-jobs-json-jobs-must-be-a-list-623a2a","errorCode":null,"errorMessage":"invalid imagegen-jobs.json: jobs must be a list","messagePattern":"invalid imagegen-jobs\\.json: jobs must be a list","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/hatch-pet/scripts/generate_pet_images.py","lineNumber":51,"sourceCode":"        return ALL_STATES\n    states = [item.strip() for item in raw.split(\",\") if item.strip()]\n    unknown = sorted(set(states) - set(ALL_STATES))\n    if unknown:\n        raise SystemExit(f\"unknown state(s): {', '.join(unknown)}\")\n    return states\n\n\ndef load_manifest(run_dir: Path) -> dict[str, object]:\n    path = run_dir / \"imagegen-jobs.json\"\n    if not path.exists():\n        raise SystemExit(f\"job manifest not found: {path}\")\n    return json.loads(path.read_text(encoding=\"utf-8\"))\n\n\ndef manifest_jobs(manifest: dict[str, object]) -> list[dict[str, object]]:\n    jobs = manifest.get(\"jobs\")\n    if not isinstance(jobs, list):\n        raise SystemExit(\"invalid imagegen-jobs.json: jobs must be a list\")\n    return [job for job in jobs if isinstance(job, dict)]\n\n\ndef select_jobs(\n    manifest: dict[str, object],\n    *,\n    states: list[str],\n    skip_base: bool,\n    job_ids: list[str],\n) -> list[dict[str, object]]:\n    selected_ids = set(job_ids)\n    if not selected_ids:\n        if not skip_base:\n            selected_ids.add(\"base\")\n        selected_ids.update(states)\n    selected = [job for job in manifest_jobs(manifest) if job.get(\"id\") in selected_ids]\n    missing = selected_ids - {str(job.get(\"id\")) for job in selected}\n    if missing:","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/hatch-pet/scripts/generate_pet_images.py#L33-L69","documentation":"Raised by manifest_jobs in generate_pet_images.py when imagegen-jobs.json parses but its 'jobs' field is not a list. This is the same schema invariant enforced by finalize_pet_run.py (error 632), checked here so the fallback generator fails early before any API call.","triggerScenarios":"manifest.get('jobs') is not a list (dict, string, null, etc.) in a manifest that otherwise parses as JSON.","commonSituations":"Corrupted or hand-edited manifest where the jobs array became an object; schema drift; a write that nulled the field.","solutions":["Ensure imagegen-jobs.json has a top-level 'jobs' array of objects.","Regenerate the manifest from the job-creation step.","Validate with a JSON schema or a one-line type check before running generate_pet_images.py."],"exampleFix":"// before (imagegen-jobs.json)\n{\"jobs\":null}\n// after\n{\"jobs\":[{\"id\":\"base\",...}]}","handlingStrategy":"type-guard","validationCode":"manifest = json.loads(Path('imagegen-jobs.json').read_text())\njobs = manifest.get('jobs')\nassert isinstance(jobs, list), 'jobs must be a list'","typeGuard":"def is_jobs_array(manifest: object) -> bool:\n    return isinstance(manifest, dict) and isinstance(manifest.get('jobs'), list)","tryCatchPattern":null,"preventionTips":["Validate the manifest schema (jobs: array) before any API call.","Regenerate rather than hand-patch corrupted manifests.","Add a JSON-schema check to CI for imagegen-jobs.json."],"tags":["manifest","schema","json","pet-pipeline"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}