{"record":{"id":"4b2071960a248bac","repo":"headroomlabs-ai/headroom","slug":"output-directory-must-be-empty-to-avoid-stale-arti","errorCode":null,"errorMessage":"output directory must be empty to avoid stale artifacts: {path}","messagePattern":"output directory must be empty to avoid stale artifacts: (.+?)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/build_python_release_smoke.py","lineNumber":59,"sourceCode":"    if re.fullmatch(r\"[A-Za-z0-9_./:=\\\\-]+\", text):\n        return text\n    return f'\"{text.replace(chr(34), chr(34) * 2)}\"'\n\n\ndef run(\n    args: list[str | os.PathLike[str]],\n    *,\n    env: dict[str, str] | None = None,\n    cwd: Path = ROOT,\n) -> None:\n    print(\"\\n> \" + \" \".join(quote_arg(arg) for arg in args), flush=True)\n    subprocess.run([str(arg) for arg in args], cwd=cwd, env=env, check=True)\n\n\ndef ensure_empty_dir(path: Path) -> None:\n    path.mkdir(parents=True, exist_ok=True)\n    if any(path.iterdir()):\n        raise SystemExit(f\"output directory must be empty to avoid stale artifacts: {path}\")\n\n\ndef build_artifacts(out_dir: Path, python_exe: str, profile: str, release: bool) -> None:\n    env = os.environ.copy()\n    env.setdefault(\"PYO3_USE_ABI3_FORWARD_COMPATIBILITY\", \"1\")\n\n    run([python_exe, \"-m\", \"maturin\", \"--version\"], env=env)\n\n    build_args = [\n        python_exe,\n        \"-m\",\n        \"maturin\",\n        \"build\",\n        \"--out\",\n        out_dir,\n        \"--interpreter\",\n        python_exe,\n    ]","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/scripts/build_python_release_smoke.py#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\npython scripts/build_python_release_smoke.py --out ./smoke-out\n# fails when ./smoke-out already has files\n\n# after\nrm -rf ./smoke-out && python scripts/build_python_release_smoke.py --out ./smoke-out","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef fresh_out_dir(path: Path) -> Path:\n    import time\n    candidate = path if not any(path.glob(\"*\")) else path.with_name(f\"{path.name}-{time.strftime('%Y%m%d-%H%M%S')}\")\n    candidate.mkdir(parents=True, exist_ok=True)\n    assert not any(candidate.iterdir()), candidate\n    return candidate","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["python","release","filesystem","smoke-test"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}