{"id":"a37174143e33f5fe","repo":"pytest-dev/pytest","slug":"cannot-create-lockfile-in-p","errorCode":null,"errorMessage":"cannot create lockfile in {p}","messagePattern":"cannot create lockfile in (.+?)","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"src/_pytest/pathlib.py","lineNumber":295,"sourceCode":"        except Exception:\n            pass\n        else:\n            _force_symlink(root, prefix + \"current\", new_path)\n            return new_path\n    else:\n        raise OSError(\n            \"could not create numbered dir with prefix \"\n            f\"{prefix} in {root} after 10 tries\"\n        )\n\n\ndef create_cleanup_lock(p: Path) -> Path:\n    \"\"\"Create a lock to prevent premature directory cleanup.\"\"\"\n    lock_path = get_lock_path(p)\n    try:\n        fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)\n    except FileExistsError as e:\n        raise OSError(f\"cannot create lockfile in {p}\") from e\n    else:\n        pid = os.getpid()\n        spid = str(pid).encode()\n        os.write(fd, spid)\n        os.close(fd)\n        if not lock_path.is_file():\n            raise OSError(\"lock path got renamed after successful creation\")\n        return lock_path\n\n\ndef register_cleanup_lock_removal(lock_path: Path, register: Any) -> Any:\n    \"\"\"Register a cleanup function for removing a lock.\"\"\"\n    pid = os.getpid()\n\n    def cleanup_on_exit(lock_path: Path = lock_path, original_pid: int = pid) -> None:\n        current_pid = os.getpid()\n        if current_pid != original_pid:\n            # fork","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/pathlib.py#L277-L313","documentation":"create_cleanup_lock opens an exclusive (O_CREAT|O_EXCL) lock file to serialize cache-dir cleanup. If the file already exists it raises OSError('cannot create lockfile in {p}'), wrapping the underlying FileExistsError. A stale lock blocks cleanup.","triggerScenarios":"A leftover .lock file in the cache/temp dir from a previous pytest process that crashed or was killed before cleanup; or two pytest processes racing over the same cache dir.","commonSituations":"Previous run killed (SIGKILL, OOM, CI cancel) leaving a stale lock; multiple workers writing to the same cache; container restarts leaving locks behind.","solutions":["Remove the stale .lock file in the cache directory (the path is echoed in the message)","Ensure pytest processes sharing a cache dir are not run concurrently","Use -p no:cacheprovider or a per-process --cachedir if concurrency is unavoidable"],"exampleFix":"// before\n# stale .pytest_cache/.../lock present\n// after\nrm -f .pytest_cache/v/cache/*.lock  # then re-run pytest","handlingStrategy":"validation","validationCode":"def ensure_no_stale_lock(cache_dir):\n    from pathlib import Path\n    for lock in Path(cache_dir).rglob('*.lock'):\n        try:\n            lock.unlink()\n        except OSError:\n            pass","typeGuard":null,"tryCatchPattern":"try:\n    create_cleanup_lock(p)\nexcept OSError:\n    # stale lock from a crashed run; remove and retry once\n    get_lock_path(p).unlink(missing_ok=True)\n    create_cleanup_lock(p)","preventionTips":["Remove stale .lock files after a crashed/killed pytest run","Avoid running multiple pytest processes against the same cache dir"],"tags":["pathlib","cache","lock","filesystem","pytest"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}