{"record":{"id":"897be271cb4f2fc8","repo":"nexu-io/open-design","slug":"job-job-get-id-has-invalid-input-images","errorCode":null,"errorMessage":"job {job.get('id')} has invalid input_images","messagePattern":"job (.+?) has invalid input_images","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/hatch-pet/scripts/generate_pet_images.py","lineNumber":212,"sourceCode":"    canonical.parent.mkdir(parents=True, exist_ok=True)\n    shutil.copy2(output_image, canonical)\n    reference = {\n        \"path\": CANONICAL_BASE_PATH,\n        \"source_job\": \"base\",\n        \"sha256\": file_sha256(canonical),\n    }\n    manifest[\"canonical_identity_reference\"] = reference\n    request_path = run_dir / \"pet_request.json\"\n    if request_path.exists():\n        request = json.loads(request_path.read_text(encoding=\"utf-8\"))\n        request[\"canonical_identity_reference\"] = reference\n        request_path.write_text(json.dumps(request, indent=2) + \"\\n\", encoding=\"utf-8\")\n\n\ndef path_list(run_dir: Path, job: dict[str, object]) -> list[Path]:\n    inputs = job.get(\"input_images\")\n    if not isinstance(inputs, list):\n        raise SystemExit(f\"job {job.get('id')} has invalid input_images\")\n    paths = []\n    for item in inputs:\n        if not isinstance(item, dict) or not isinstance(item.get(\"path\"), str):\n            raise SystemExit(f\"job {job.get('id')} has invalid input image entry\")\n        path = (run_dir / item[\"path\"]).resolve()\n        if not path.is_relative_to(run_dir):\n            raise SystemExit(f\"path traversal detected in input_images for job {job.get('id')}\")\n        if not path.is_file():\n            raise SystemExit(f\"input image for job {job.get('id')} not found: {path}\")\n        paths.append(path)\n    return paths\n\n\ndef main() -> None:\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument(\"--run-dir\", required=True)\n    parser.add_argument(\"--model\", default=\"gpt-image-2\")\n    parser.add_argument(\"--size\", default=\"1024x1024\")","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/hatch-pet/scripts/generate_pet_images.py#L194-L230","documentation":"Raised by path_list when a job's input_images field is present but is not a list. The generator iterates input_images to attach reference images to the OpenAI images/edits request, so any non-list shape is unrecoverable.","triggerScenarios":"The imagegen-jobs.json manifest for the job has input_images set to a string, dict, number, or null (e.g. someone hand-edited the manifest, or an earlier run wrote input_images as a single object instead of a list).","commonSituations":"Manual edits to imagegen-jobs.json; a different version of prepare_pet_run.py that emits a different input_images shape; corrupt/partial manifest from an interrupted run.","solutions":["Open run_dir/imagegen-jobs.json and find the job whose id matches the message.","Fix input_images to a list of {\"path\": \"<relative>\", \"role\": \"...\"} objects, matching the shape prepare_pet_run.py writes.","If unsure of the intended inputs, regenerate the run dir with prepare_pet_run.py instead of patching by hand.","Rerun generate_pet_images.py scoped to --job-id <id>."],"exampleFix":"// before (manifest)\n\"input_images\": \"references/canonical-base.png\"\n\n// after\n\"input_images\": [\n  {\"path\": \"references/canonical-base.png\", \"role\": \"canonical identity reference\"}\n]","handlingStrategy":"validation","validationCode":"def assert_input_images(job: dict) -> list:\n    inputs = job.get(\"input_images\")\n    if not isinstance(inputs, list):\n        raise SystemExit(f\"job {job.get('id')} has invalid input_images\")\n    return inputs","typeGuard":"from typing import Any\n\ndef is_string_list(value: Any) -> bool:\n    return isinstance(value, list)","tryCatchPattern":null,"preventionTips":["Treat imagegen-jobs.json as generated output: regenerate with prepare_pet_run.py instead of hand-editing.","Validate the manifest with a JSON-schema check before running generation.","Version the manifest schema_version field and reject unknown versions."],"tags":["manifest","json-schema","validation","system-exit"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}