nexu-io/open-design · error · SystemExit

{run_dir} already exists and is not empty; pass --force to r

Error message

{run_dir} already exists and is not empty; pass --force to reuse it

What it means

Raised by prepare_pet_run.py when the resolved run directory already exists and contains at least one entry, and --force was not passed. It is a deliberate guard so an in-progress or previously-generated pet run is never silently overwritten. The script resolves run_dir from --output-dir (or default_output_dir(pet_id)) and treats any non-empty target as occupied.

Source

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

    raw_reference_paths = [
        Path(raw_path).expanduser().resolve() for raw_path in args.reference
    ]

    args.display_name = infer_name(args, raw_reference_paths)
    args.pet_name = (args.pet_name or args.display_name).strip()
    args.description = infer_description(args, raw_reference_paths)
    args.pet_notes = infer_pet_notes(args, raw_reference_paths)
    args.pet_id = slugify(args.pet_id or args.pet_name or args.display_name)
    if not args.pet_id:
        raise SystemExit("pet id must contain at least one letter or digit")

    run_dir = (
        Path(args.output_dir).expanduser().resolve()
        if args.output_dir
        else default_output_dir(args.pet_id).resolve()
    )
    if run_dir.exists() and any(run_dir.iterdir()) and not args.force:
        raise SystemExit(
            f"{run_dir} already exists and is not empty; pass --force to reuse it"
        )
    run_dir.mkdir(parents=True, exist_ok=True)

    ref_dir = run_dir / "references"
    prompt_dir = run_dir / "prompts"
    row_prompt_dir = prompt_dir / "rows"
    for directory in [
        ref_dir,
        prompt_dir,
        row_prompt_dir,
        run_dir / "decoded",
        run_dir / "qa",
    ]:
        directory.mkdir(parents=True, exist_ok=True)

    copied_refs: list[dict[str, object]] = []
    copied_ref_paths: list[Path] = []

View on GitHub (pinned to 5be4028344)

Solutions

  1. Pass --force if you intentionally want to reuse the existing run_dir.
  2. Move or delete the existing run_dir before re-running, e.g. rm -rf <run_dir>.
  3. Use a distinct --pet-id (which changes default_output_dir) or a fresh --output-dir for the new attempt.
  4. If the directory is unexpectedly non-empty (leftover dotfiles), inspect run_dir.iterdir() and clean the stray entries.

Example fix

# before
python skills/hatch-pet/scripts/prepare_pet_run.py --pet-name "Fenrir"
# after (reuse intentionally)
python skills/hatch-pet/scripts/prepare_pet_run.py --pet-name "Fenrir" --force
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
run_dir = Path(args.output_dir or default_output_dir(args.pet_id)).expanduser().resolve()
if run_dir.exists() and any(run_dir.iterdir()) and not args.force:
    print(f"refusing to overwrite {run_dir}; pass --force or pick a new --output-dir")
    raise SystemExit(2)

Prevention

When it happens

Trigger: Running prepare_pet_run.py a second time with the same --pet-id (same default_output_dir), or pointing --output-dir at a folder that already holds files; re-running after a partial/failed generation without cleaning up.

Common situations: Iterating on a pet design and forgetting the previous run is still on disk; CI/local rerun after a crash left the run_dir partially populated; two teammates sharing a workspace whose default output root collides.

Related errors


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