pytest-dev/pytest · error · OSError
lock path got renamed after successful creation
Error message
lock path got renamed after successful creation
What it means
Raised by create_cleanup_lock after a lock file is successfully created and written, but is_found.is_file() returns False immediately after (lines 297-302). This detects a TOCTOU race where another process moved or removed the lock between creation and the existence check. It signals filesystem instability or concurrent cleanup interference.
Solutions
- Point pytest's basetemp at a local, non-synced filesystem.
- Avoid concurrent pytest runs sharing the same tmp root.
- Exclude the tmp dir from sync/antivirus scanning.
Example fix
// before pytest --basetemp=~/Dropbox/pytest // after pytest --basetemp=/tmp/pytest-run
Defensive patterns
Strategy: fallback
Validate before calling
import os
if any(sync in str(p) for sync in ['Dropbox', 'OneDrive', 'icloud']):
raise RuntimeError('basetemp on a synced volume is unsafe') Type guard
def _on_local_fs(p) -> bool:
import os
return not any(s in str(p) for s in ('Dropbox', 'OneDrive', 'icloud')) Prevention
- Keep pytest basetemp off cloud-synced or network volumes.
- Avoid overlapping concurrent cleanup runs.
When it happens
Trigger: A concurrent cleanup process deletes or renames the lock right after creation; antivirus or sync software (Dropbox, OneDrive) moving newly created files; network filesystems with delayed visibility.
Common situations: Cloud-synced tmp directories; NFS with caching; concurrent pytest runs with overlapping cleanup windows.
Related errors
- could not create numbered dir with prefix
- cannot create lockfile in
- {path}
- Can't find module at location
- Could not resolve for
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/64e5b38217ee42a1.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/pathlib.py:302
"could not create numbered dir with prefix "
f"{prefix} in {root} after 10 tries"
)
def create_cleanup_lock(p: Path) -> Path:
"""Create a lock to prevent premature directory cleanup."""
lock_path = get_lock_path(p)
try:
fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
except FileExistsError as e:
raise OSError(f"cannot create lockfile in {p}") from e
else:
pid = os.getpid()
spid = str(pid).encode()
os.write(fd, spid)
os.close(fd)
if not lock_path.is_file():
raise OSError("lock path got renamed after successful creation")
return lock_path
def register_cleanup_lock_removal(lock_path: Path, register: Any) -> Any:
"""Register a cleanup function for removing a lock."""
pid = os.getpid()
def cleanup_on_exit(lock_path: Path = lock_path, original_pid: int = pid) -> None:
current_pid = os.getpid()
if current_pid != original_pid:
# fork
return
try:
lock_path.unlink()
except OSError:
pass
return register(cleanup_on_exit)View on GitHub (pinned to 0d6fbdeffa)