nexu-io/open-design · error · SystemExit
expected PNG or WebP, got {image.format}
Error message
expected PNG or WebP, got {image.format} What it means
Raised by validate_spritesheet when the spritesheet's detected format is neither PNG nor WEBP. The packager converts PNG to lossless WEBP, or copies WEBP verbatim; any other format is rejected because the conversion path does not trust it.
Source
Thrown at skills/hatch-pet/scripts/package_custom_pet.py:36
def default_codex_home() -> Path:
return Path(os.environ.get("CODEX_HOME") or "~/.codex").expanduser().resolve()
def slugify(value: str) -> str:
value = value.strip().lower()
value = re.sub(r"[^a-z0-9]+", "-", value)
value = re.sub(r"-{2,}", "-", value)
return value.strip("-")
def validate_spritesheet(path: Path) -> str:
with Image.open(path) as image:
if image.size != ATLAS_SIZE:
raise SystemExit(
f"expected {ATLAS_SIZE[0]}x{ATLAS_SIZE[1]}, got {image.width}x{image.height}"
)
if image.format not in {"PNG", "WEBP"}:
raise SystemExit(f"expected PNG or WebP, got {image.format}")
return str(image.format)
def write_webp_spritesheet(source: Path, target: Path, source_format: str) -> None:
if source_format == "WEBP":
shutil.copy2(source, target)
return
with Image.open(source) as image:
target.parent.mkdir(parents=True, exist_ok=True)
image.convert("RGBA").save(
target,
format="WEBP",
lossless=True,
quality=100,
method=6,
)
View on GitHub (pinned to 5be4028344)
Solutions
- Re-export/save the spritesheet as PNG (lossless) or WEBP.
- Convert in place: python -c "from PIL import Image; Image.open('sheet.jpg').save('sheet.png')".
- Re-run package_custom_pet.py --spritesheet sheet.png.
- Confirm format: python -c "from PIL import Image; print(Image.open('sheet.png').format)" prints PNG or WEBP.
Example fix
// before
python package_custom_pet.py --spritesheet sheet.jpg ...
# SystemExit: expected PNG or WebP, got JPEG
// after
python -c "from PIL import Image; Image.open('sheet.jpg').save('sheet.png')"
python package_custom_pet.py --spritesheet sheet.png ... Defensive patterns
Strategy: validation
Validate before calling
from PIL import Image
def check_format(path):
with Image.open(path) as im:
if im.format not in {"PNG", "WEBP"}:
raise SystemExit(f"expected PNG or WEBP, got {im.format}") Type guard
def is_png_or_webp(path) -> bool:
with Image.open(path) as im:
return im.format in {"PNG", "WEBP"} Prevention
- Export spritesheets as PNG (lossless) or WEBP; avoid JPEG/GIF for sprite atlases.
- Verify format with Image.open(path).format before packaging.
- Standardize the export preset in your art tool to PNG.
When it happens
Trigger: Passing a JPEG, GIF, BMP, TIFF, or AVIF spritesheet. PIL reports image.format as e.g. "JPEG", which is not in {"PNG", "WEBP"}.
Common situations: Exported the sheet as JPEG (lossy, chroma artifacts); downloaded a GIF/WEBP variant that PIL identifies differently; saved from a tool that defaults to JPEG.
Related errors
- expected {ATLAS_SIZE[0]}x{ATLAS_SIZE[1]}, got {image.width}x
- invalid JSON in ${filePath}: ${message}
- ${filePath} must contain a JSON object
- ARTIFACT_MANIFEST_INVALID
- ARTIFACT_MANIFEST_REQUIRED
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/6c2fdd86e0819b7b.
Report an issue: GitHub.