nexu-io/open-design · error · SystemExit
invalid imagegen-jobs.json: jobs must be a list
Error message
invalid imagegen-jobs.json: jobs must be a list
What it means
Raised by require_complete_jobs in finalize_pet_run.py when imagegen-jobs.json parses but its 'jobs' field is not a JSON list. The manifest schema requires jobs to be an array of job objects; any other shape is treated as corruption.
Source
Thrown at skills/hatch-pet/scripts/finalize_pet_run.py:186
raise SystemExit(
f"job {job_id} source image is inside the pet run directory; "
"do not use locally generated row artifacts as visual sources"
)
generated_root = default_generated_images_root()
if not is_relative_to(source, generated_root) or not source.name.startswith("ig_"):
raise SystemExit(
f"job {job_id} source image is not a built-in $imagegen output under "
f"{generated_root}/.../ig_*.png"
)
validate_hash(job, source=source, output=output, job_id=job_id)
def require_complete_jobs(run_dir: Path, *, allow_synthetic_test_sources: bool) -> None:
manifest_path = run_dir / "imagegen-jobs.json"
manifest = load_json(manifest_path)
jobs = manifest.get("jobs")
if not isinstance(jobs, list):
raise SystemExit("invalid imagegen-jobs.json: jobs must be a list")
incomplete = [
str(job.get("id"))
for job in jobs
if isinstance(job, dict) and job.get("status", "pending") != "complete"
]
if incomplete:
raise SystemExit(
"imagegen jobs are not complete; run pet_job_status.py and finish: "
+ ", ".join(incomplete)
)
for job in jobs:
if isinstance(job, dict):
validate_completed_job_source(
job,
run_dir=run_dir,
allow_synthetic_test_sources=allow_synthetic_test_sources,
)
View on GitHub (pinned to 5be4028344)
Solutions
- Open imagegen-jobs.json and ensure the top-level 'jobs' key is a JSON array of job objects.
- Regenerate the manifest from the job-creation step that originally produced it.
- Validate the file with `python -c "import json;print(type(json.load(open('imagegen-jobs.json'))['jobs']))"` before re-running finalize.
Example fix
// before (imagegen-jobs.json)
{"jobs":{"base":{...}}}
// after
{"jobs":[{"id":"base",...}]} Defensive patterns
Strategy: type-guard
Validate before calling
manifest = json.loads(Path('imagegen-jobs.json').read_text())
if not isinstance(manifest.get('jobs'), list):
raise ValueError('imagegen-jobs.json jobs must be a list') Type guard
from typing import Any, TypeGuard
def is_job_list(manifest: Any) -> TypeGuard[dict[str, list[dict[str, object]]]]:
return isinstance(manifest, dict) and isinstance(manifest.get('jobs'), list) Prevention
- Validate imagegen-jobs.json against a JSON schema with jobs: array before running finalize.
- Never hand-edit the jobs field into a different shape.
- Regenerate corrupted manifests from the job-creation step.
When it happens
Trigger: json.loads(run_dir/'imagegen-jobs.json') succeeds but manifest.get('jobs') is a dict, string, number, null, or missing.
Common situations: Hand-editing imagegen-jobs.json and accidentally turning the jobs array into an object keyed by id; a partial write that left 'jobs' as null; schema drift from an older manifest version.
Related errors
- invalid imagegen-jobs.json: jobs must be a list
- existing config at ${where} is not a JSON object
- [CompetitorsPlan] Top-level must be a dict of {entity: {targ
- running-left mirror source must be decoded/running-right.png
- running-left mirror output must be decoded/running-left.png
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/3a6a02ed35299911.
Report an issue: GitHub.