nexu-io/open-design · warning · SystemExit

{target_dir} already contains pet files; pass --force to ove

Error message

{target_dir} already contains pet files; pass --force to overwrite

What it means

Raised by package_custom_pet.py when the target pet directory already contains spritesheet.webp or pet.json and --force was not passed. This protects an existing installed pet from being silently overwritten.

Source

Thrown at skills/hatch-pet/scripts/package_custom_pet.py:89

        raise SystemExit("pet name is required")
    pet_id = slugify(raw_pet_name)
    if not pet_id:
        raise SystemExit("pet name must contain at least one letter or digit")
    display_name = (args.display_name or raw_pet_name).strip()

    source = Path(args.spritesheet).expanduser().resolve()
    source_format = validate_spritesheet(source)
    target_dir = (
        Path(args.output_dir).expanduser().resolve()
        if args.output_dir
        else Path(args.codex_home).expanduser().resolve() / "pets" / pet_id
    )
    target_dir.mkdir(parents=True, exist_ok=True)

    target_sheet = target_dir / "spritesheet.webp"
    manifest_path = target_dir / "pet.json"
    if not args.force and (target_sheet.exists() or manifest_path.exists()):
        raise SystemExit(f"{target_dir} already contains pet files; pass --force to overwrite")

    write_webp_spritesheet(source, target_sheet, source_format)
    manifest = {
        "id": pet_id,
        "displayName": display_name,
        "description": args.description,
        "spritesheetPath": target_sheet.name,
    }
    manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")

    print(
        json.dumps(
            {"ok": True, "pet_dir": str(target_dir), "manifest": str(manifest_path)}, indent=2
        )
    )


if __name__ == "__main__":

View on GitHub (pinned to 5be4028344)

Solutions

  1. Pass --force to overwrite the existing spritesheet.webp and pet.json.
  2. Or pick a different --pet-name / --output-dir to keep both versions.
  3. Confirm the existing pet.json is not one you want to preserve before using --force.
  4. Re-run with the chosen option.

Example fix

// before
python package_custom_pet.py --pet-name Sprite --description "..." --spritesheet sheet.png
# SystemExit: .../pets/sprite already contains pet files; pass --force to overwrite

// after
python package_custom_pet.py --pet-name Sprite --description "..." --spritesheet sheet.png --force
Defensive patterns

Strategy: validation

Validate before calling

def target_is_clean(target_dir: Path, force: bool) -> bool:
    if force:
        return True
    sheet = target_dir / "spritesheet.webp"
    manifest = target_dir / "pet.json"
    return not (sheet.exists() or manifest.exists())

Prevention

When it happens

Trigger: Re-packaging a pet into the same target_dir (default ${CODEX_HOME}/pets/<pet-id> or a custom --output-dir) where a previous package already wrote its files.

Common situations: Iterating on the same pet name without --force; reinstalling over an existing pet to update its spritesheet; default target resolving to a dir you already populated.

Related errors


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