nexu-io/open-design · error · SystemExit
running-left mirrored output is not an exact horizontal mirr
Error message
running-left mirrored output is not an exact horizontal mirror of running-right
What it means
Raised by validate_mirror_hash after PIL loads both images: it computes expected = ImageOps.mirror(source.convert('RGBA')) and compares raw bytes/size against the output. If they differ by even one pixel, the deterministic-mirror contract is violated and finalize aborts.
Source
Thrown at skills/hatch-pet/scripts/finalize_pet_run.py:118
raise SystemExit(f"running-left mirror source image no longer exists: {source}")
if not output.is_file():
raise SystemExit(f"running-left mirrored output is missing: {output}")
if source.name != "running-right.png" or source.parent.name != "decoded":
raise SystemExit("running-left mirror source must be decoded/running-right.png")
if output.name != "running-left.png" or output.parent.name != "decoded":
raise SystemExit("running-left mirror output must be decoded/running-left.png")
if file_sha256(source) != expected_source_hash:
raise SystemExit("running-left mirror source hash does not match imagegen-jobs.json")
if file_sha256(output) != expected_output_hash:
raise SystemExit(
"running-left mirrored output hash does not match imagegen-jobs.json; "
"rerun derive_running_left_from_running_right.py"
)
with Image.open(source) as source_image, Image.open(output) as output_image:
expected = ImageOps.mirror(source_image.convert("RGBA"))
actual = output_image.convert("RGBA")
if expected.size != actual.size or expected.tobytes() != actual.tobytes():
raise SystemExit(
"running-left mirrored output is not an exact horizontal mirror of running-right"
)
def validate_completed_job_source(
job: dict[str, object],
*,
run_dir: Path,
allow_synthetic_test_sources: bool,
) -> None:
job_id = str(job.get("id") or "")
source = manifest_path(job.get("source_path"), run_dir=run_dir, field="source_path", job_id=job_id)
output = manifest_path(job.get("output_path"), run_dir=run_dir, field="output_path", job_id=job_id)
blocked_flags = [
flag
for flag in ("deterministic_pet_row", "cute_raster_row", "local_raster_row")
if job.get(flag)View on GitHub (pinned to 5be4028344)
Solutions
- Regenerate decoded/running-left.png exclusively via derive_running_left_from_running_right.py, which uses ImageOps.mirror and is byte-identical by construction.
- If a custom left frame is genuinely desired, do not use source_provenance='deterministic-mirror'; instead generate it with $imagegen and record built-in-imagegen provenance.
- Verify the source running-right.png is RGBA-clean (no embedded color profile altering decode) before deriving.
Defensive patterns
Strategy: validation
Validate before calling
from PIL import Image, ImageOps
with Image.open(source) as s, Image.open(output) as o:
expected = ImageOps.mirror(s.convert('RGBA'))
actual = o.convert('RGBA')
assert expected.size == actual.size and expected.tobytes() == actual.tobytes(), 'not an exact mirror' Prevention
- Only use derive_running_left_from_running_right.py (ImageOps.mirror) to produce running-left.png.
- Never substitute an AI-generated left-facing frame under deterministic-mirror provenance.
- Save PNGs without alpha premultiplication or color-profile embedding to keep bytes stable.
When it happens
Trigger: The on-disk decoded/running-left.png is not a pixel-exact horizontal flip of decoded/running-right.png, even though both SHA-256 fields happen to match their files (e.g. someone replaced running-left.png with a hand-drawn or AI-generated left-facing frame and updated output_sha256 to match).
Common situations: Using an AI image edit to 'improve' the left-facing frame instead of the deterministic flip; saving with a different RGBA alpha handling that shifts bytes; an editor that premultiplies alpha on save.
Related errors
- running-left mirror source hash does not match imagegen-jobs
- running-left mirrored output hash does not match imagegen-jo
- running-left mirrored output is missing: {output}
- 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/0a6ef53e1c5dda7d.
Report an issue: GitHub.