headroomlabs-ai/headroom · error · SystemExit
output directory must be empty to avoid stale artifacts: {pa
Error message
output directory must be empty to avoid stale artifacts: {path} What it means
ensure_empty_dir() in the Python release smoke script creates the output directory and refuses to proceed if it already contains anything. The check exists so each smoke run verifies artifacts it built itself, never stale wheels or sdists from an earlier run.
Source
Thrown at scripts/build_python_release_smoke.py:59
if re.fullmatch(r"[A-Za-z0-9_./:=\\-]+", text):
return text
return f'"{text.replace(chr(34), chr(34) * 2)}"'
def run(
args: list[str | os.PathLike[str]],
*,
env: dict[str, str] | None = None,
cwd: Path = ROOT,
) -> None:
print("\n> " + " ".join(quote_arg(arg) for arg in args), flush=True)
subprocess.run([str(arg) for arg in args], cwd=cwd, env=env, check=True)
def ensure_empty_dir(path: Path) -> None:
path.mkdir(parents=True, exist_ok=True)
if any(path.iterdir()):
raise SystemExit(f"output directory must be empty to avoid stale artifacts: {path}")
def build_artifacts(out_dir: Path, python_exe: str, profile: str, release: bool) -> None:
env = os.environ.copy()
env.setdefault("PYO3_USE_ABI3_FORWARD_COMPATIBILITY", "1")
run([python_exe, "-m", "maturin", "--version"], env=env)
build_args = [
python_exe,
"-m",
"maturin",
"build",
"--out",
out_dir,
"--interpreter",
python_exe,
]View on GitHub (pinned to 322425c43b)
Solutions
- Point `--out` at a fresh directory (the default in release_smoke_all.py already appends a version + timestamp stamp).
- Or empty the directory first: `rm -rf <out_dir>/*` and rerun.
- If this repeats in CI, make the job clean or unique-name its output dir instead of disabling the check.
Example fix
# before python scripts/build_python_release_smoke.py --out ./smoke-out # fails when ./smoke-out already has files # after rm -rf ./smoke-out && python scripts/build_python_release_smoke.py --out ./smoke-out
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def fresh_out_dir(path: Path) -> Path:
import time
candidate = path if not any(path.glob("*")) else path.with_name(f"{path.name}-{time.strftime('%Y%m%d-%H%M%S')}")
candidate.mkdir(parents=True, exist_ok=True)
assert not any(candidate.iterdir()), candidate
return candidate Prevention
- Let the orchestrator's timestamped default output path do its job instead of pinning --out.
- In CI, clean or uniquely name the output directory per run attempt.
- Treat this error as a hint that a previous run left state, and investigate why before deleting.
When it happens
Trigger: Passing `--out <dir>` pointing at a directory that already holds files; rerunning the smoke into a hand-created output dir; a previous crashed run leaving partial maturin output behind.
Common situations: Iterating on release tooling and reusing a fixed output path like `./dist`; CI retrying a job into a cached workspace directory; a timeout killing maturin mid-build so the dir is dirty on the next attempt.
Related errors
- output directory must be empty to avoid stale artifacts: {pa
- binary cache directory parent is not writable: {dest.parent}
- binary cache directory is not writable: {dest.parent}
- {wheel.name} metadata missing {expected_line!r}
- nothing to run: --skip-npm and --skip-python were both set
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/4b2071960a248bac.
Report an issue: GitHub.