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
Thrown by job_list() in derive_running_left_from_running_right.py when the parsed imagegen-jobs.json has a top-level 'jobs' key that is not a JSON array. The downstream logic iterates jobs as a list, so any other shape (object, string, number, null) is treated as a corrupt manifest.
Source
Thrown at skills/hatch-pet/scripts/derive_running_left_from_running_right.py:25
import hashlib
import json
from datetime import datetime, timezone
from pathlib import Path
from PIL import Image, ImageOps
def load_manifest(run_dir: Path) -> dict[str, object]:
path = run_dir / "imagegen-jobs.json"
if not path.exists():
raise SystemExit(f"job manifest not found: {path}")
return json.loads(path.read_text(encoding="utf-8"))
def job_list(manifest: dict[str, object]) -> list[dict[str, object]]:
jobs = manifest.get("jobs")
if not isinstance(jobs, list):
raise SystemExit("invalid imagegen-jobs.json: jobs must be a list")
return [job for job in jobs if isinstance(job, dict)]
def find_job(manifest: dict[str, object], job_id: str) -> dict[str, object]:
for job in job_list(manifest):
if job.get("id") == job_id:
return job
raise SystemExit(f"unknown job id: {job_id}")
def file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as file:
for chunk in iter(lambda: file.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
View on GitHub (pinned to 5be4028344)
Solutions
- Re-generate imagegen-jobs.json with the pipeline so 'jobs' is a list of job objects each carrying an 'id'.
- If migrating, transform the object form to a list: jobs = list(old_object.values()) and ensure each entry has an 'id' field.
- Validate the manifest with a JSON schema or a quick python check before invoking the script.
Example fix
// before
{"jobs": {"running-right": {...}, "running-left": {...}}}
// after
{"jobs": [{"id": "running-right", ...}, {"id": "running-left", "mirror_policy": {"may_derive_from": "running-right"}}]} Defensive patterns
Strategy: type-guard
Validate before calling
import json
def load_jobs(run_dir):
data = json.loads((run_dir / "imagegen-jobs.json").read_text(encoding="utf-8"))
jobs = data.get("jobs")
if not isinstance(jobs, list):
raise SystemExit("jobs must be a list")
return jobs Type guard
def is_valid_manifest(data) -> bool:
return isinstance(data, dict) and isinstance(data.get("jobs"), list) and all(isinstance(j, dict) for j in data["jobs"]) Prevention
- Only write imagegen-jobs.json via the pipeline that emits a list of job objects.
- Validate the manifest shape with a JSON schema before running derive.
When it happens
Trigger: Run derive_running_left_from_running_right.py --run-dir <dir> where imagegen-jobs.json exists but its 'jobs' field is not a list — e.g. it is an object keyed by job id, or the file was hand-edited/truncated.
Common situations: Manifest written by a different version of the pipeline that used an object keyed by id; partial/corrupted JSON write; manual edit that wrapped jobs in another object.
Related errors
- unknown job id: {job_id}
- job manifest not found: {path}
- running-right must be complete before deriving running-left
- running-left is not configured for conditional mirroring
- job {job_id} has no {field}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/ce2306854be35ca6.
Report an issue: GitHub.