nexu-io/open-design · error · SystemExit

invalid chroma key color: {value}; expected #RRGGBB

Error message

invalid chroma key color: {value}; expected #RRGGBB

What it means

Raised by parse_hex_color in prepare_pet_run.py when the --chroma-key value does not match the regex #[0-9a-fA-F]{6} (and is not the default "auto", which is handled earlier in choose_chroma_key). The chroma key must be a 6-digit hex color like #FF00FF because it is sliced into R/G/B byte pairs.

Source

Thrown at skills/hatch-pet/scripts/prepare_pet_run.py:306

        "cell_width": ATLAS["cell_width"],
        "cell_height": ATLAS["cell_height"],
        "safe_margin_x": LAYOUT_GUIDE_SAFE_MARGIN_X,
        "safe_margin_y": LAYOUT_GUIDE_SAFE_MARGIN_Y,
        "usage": "layout guide input only; do not copy visible guide lines into generated sprite strips",
    }


def create_layout_guides(run_dir: Path) -> list[dict[str, object]]:
    guide_dir = run_dir / LAYOUT_GUIDE_DIR
    return [
        create_layout_guide(guide_dir / f"{state}.png", state, frames)
        for state, _row, frames, _purpose in ROWS
    ]


def parse_hex_color(value: str) -> tuple[int, int, int]:
    if not re.fullmatch(r"#[0-9a-fA-F]{6}", value):
        raise SystemExit(f"invalid chroma key color: {value}; expected #RRGGBB")
    return tuple(int(value[index : index + 2], 16) for index in (1, 3, 5))


def rgb_to_hex(rgb: tuple[int, int, int]) -> str:
    return f"#{rgb[0]:02X}{rgb[1]:02X}{rgb[2]:02X}"


def color_distance(left: tuple[int, int, int], right: tuple[int, int, int]) -> float:
    return math.sqrt(sum((left[index] - right[index]) ** 2 for index in range(3)))


def sampled_reference_pixels(paths: list[Path]) -> list[tuple[int, int, int]]:
    pixels: list[tuple[int, int, int]] = []
    for path in paths:
        with Image.open(path) as opened:
            image = opened.convert("RGBA")
            image.thumbnail((128, 128), Image.Resampling.LANCZOS)
            data = image.tobytes()

View on GitHub (pinned to 5be4028344)

Solutions

  1. Pass a 6-digit uppercase or lowercase hex with a leading # (e.g. --chroma-key #FF00FF).
  2. Or omit the flag to use --chroma-key auto, which picks a safe key from the reference image.
  3. Validate against the same regex before running if generating the value programmatically.
  4. Re-run prepare_pet_run.py.

Example fix

// before
python prepare_pet_run.py --chroma-key FF00FF --reference cat.png
# SystemExit: invalid chroma key color: FF00FF; expected #RRGGBB

// after
python prepare_pet_run.py --chroma-key "#FF00FF" --reference cat.png
Defensive patterns

Strategy: validation

Validate before calling

import re

def parse_hex_color(value: str):
    if not re.fullmatch(r"#[0-9a-fA-F]{6}", value):
        raise SystemExit(f"invalid chroma key color: {value}; expected #RRGGBB")

Type guard

import re

def is_hex_color(value: str) -> bool:
    return bool(re.fullmatch(r"#[0-9a-fA-F]{6}", value))

Prevention

When it happens

Trigger: Passing --chroma-key without a leading # (e.g. FF00FF), with 3-digit shorthand (#F0F), with extra characters (#FF00FF00), or with values outside 0-9a-f.

Common situations: Copying a hex from a color picker that omits #; using CSS 3-digit shorthand; passing an 8-digit RGBA hex; typos like #GGGGGG.

Related errors


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