nexu-io/open-design · error · SystemExit

job {job_id} source image is not a built-in $imagegen output

Error message

job {job_id} source image is not a built-in $imagegen output under {generated_root}/.../ig_*.png

What it means

Raised by validate_completed_job_source when a built-in-imagegen job's source_path is not located under default_generated_images_root() ($CODEX_HOME/generated_images) or its filename does not start with 'ig_'. This enforces that the recorded source is a genuine Codex $imagegen output artifact.

Source

Thrown at skills/hatch-pet/scripts/finalize_pet_run.py:174

        return

    if job.get("source_provenance") == "deterministic-mirror":
        validate_mirror_hash(job, source=source, output=output, job_id=job_id)
        return

    if job.get("source_provenance") != "built-in-imagegen":
        raise SystemExit(
            f"job {job_id} was not recorded as a built-in $imagegen output; "
            "use record_imagegen_result.py with the selected $CODEX_HOME/generated_images/.../ig_*.png file"
        )
    if is_relative_to(source, run_dir):
        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:

View on GitHub (pinned to 5be4028344)

Solutions

  1. Set CODEX_HOME (or rely on ~/.codex) so default_generated_images_root() matches the directory holding the ig_*.png file.
  2. Use record_imagegen_result.py to point source_path at the real $CODEX_HOME/generated_images/.../ig_*.png file.
  3. Confirm the source filename retains the original ig_ prefix assigned by Codex imagegen.

Example fix

// before (env)
CODEX_HOME=/custom/codex  # but source is under ~/.codex/generated_images
// after
unset CODEX_HOME  # or export CODEX_HOME=$HOME/.codex
Defensive patterns

Strategy: validation

Validate before calling

import os
from pathlib import Path
generated_root = Path(os.environ.get('CODEX_HOME') or '~/.codex').expanduser().resolve() / 'generated_images'
if not is_relative_to(source, generated_root) or not source.name.startswith('ig_'):
    raise RuntimeError(f'source must be under {generated_root}/.../ig_*.png')

Prevention

When it happens

Trigger: is_relative_to(source, generated_root) is false OR source.name does not start with 'ig_'. The CODEX_HOME env var may resolve somewhere unexpected, or the source file is not a Codex-generated ig_*.png.

Common situations: CODEX_HOME unset or pointing at a non-default location so generated_root differs from where the file lives; recording a manually named PNG instead of the original ig_*.png; sourcing from a different tool's output directory.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/90061a46737e2327. Report an issue: GitHub.