{"record":{"id":"7c8022eccf1e9abc","repo":"nexu-io/open-design","slug":"imagegen-jobs-are-not-complete-run-pet-job-status","errorCode":null,"errorMessage":"imagegen jobs are not complete; run pet_job_status.py and finish: {', '.join(incomplete)}","messagePattern":"imagegen jobs are not complete; run pet_job_status\\.py and finish: (.+?)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/hatch-pet/scripts/finalize_pet_run.py","lineNumber":193,"sourceCode":"            f\"job {job_id} source image is not a built-in $imagegen output under \"\n            f\"{generated_root}/.../ig_*.png\"\n        )\n    validate_hash(job, source=source, output=output, job_id=job_id)\n\n\ndef require_complete_jobs(run_dir: Path, *, allow_synthetic_test_sources: bool) -> None:\n    manifest_path = run_dir / \"imagegen-jobs.json\"\n    manifest = load_json(manifest_path)\n    jobs = manifest.get(\"jobs\")\n    if not isinstance(jobs, list):\n        raise SystemExit(\"invalid imagegen-jobs.json: jobs must be a list\")\n    incomplete = [\n        str(job.get(\"id\"))\n        for job in jobs\n        if isinstance(job, dict) and job.get(\"status\", \"pending\") != \"complete\"\n    ]\n    if incomplete:\n        raise SystemExit(\n            \"imagegen jobs are not complete; run pet_job_status.py and finish: \"\n            + \", \".join(incomplete)\n        )\n    for job in jobs:\n        if isinstance(job, dict):\n            validate_completed_job_source(\n                job,\n                run_dir=run_dir,\n                allow_synthetic_test_sources=allow_synthetic_test_sources,\n            )\n\n\ndef review_failures(review: dict[str, object]) -> list[str]:\n    rows = review.get(\"rows\")\n    if not isinstance(rows, list):\n        return [\"review did not contain row-level results\"]\n    failures = []\n    for row in rows:","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/hatch-pet/scripts/finalize_pet_run.py#L175-L211","documentation":"Raised by require_complete_jobs when one or more jobs have a status other than 'complete' (status defaults to 'pending' when absent). Finalize refuses to run until every job in the manifest reports complete, and the message lists the offending job ids.","triggerScenarios":"Any job dict where job.get('status','pending') != 'complete' is collected into the incomplete list; if that list is non-empty, finalize aborts and names the ids.","commonSituations":"Invoking finalize before all $imagegen jobs have finished; a job stuck in 'pending' or 'running' after a failed imagegen attempt; a job reopened by queue_pet_repairs.py that was never re-run.","solutions":["Run pet_job_status.py to see current statuses, then drive each incomplete job to completion via $imagegen or generate_pet_images.py.","If a job was reopened by queue_pet_repairs.py, regenerate that row with $imagegen and re-record the result.","Re-run finalize_pet_run.py only after pet_job_status.py shows all jobs complete."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"incomplete = [str(j.get('id')) for j in jobs if isinstance(j, dict) and j.get('status','pending') != 'complete']\nif incomplete:\n    raise RuntimeError(f'finish jobs first: {incomplete}')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run pet_job_status.py and confirm all-complete before invoking finalize.","Drive reopened repair jobs back to complete via $imagegen.","Treat any non-complete status as a blocker, not a skip."],"tags":["manifest","job-status","workflow","pet-pipeline"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}