pytest-dev/pytest · error · OSError
cannot create lockfile in
Error message
cannot create lockfile in {p} What it means
Raised by create_cleanup_lock when os.open with O_EXCL fails because the lock file already exists. The lock (a '.lock' sibling to a directory, line 291-295) prevents concurrent cleanup of numbered tmp dirs; an existing lock means another process holds it. The original FileExistsError is chained via 'from e' and re-raised as OSError.
Solutions
- Remove the stale lock file manually: rm <dir>.lock (after confirming no live process holds it).
- Use separate basetemp directories per concurrent run (--basetemp).
- Run the cleanup lock removal or rely on pytest's atexit hooks to reap stale locks.
Example fix
// before (stale lock blocks run) rm -rf /tmp/pytest-of-user/.lock # may be unsafe if a run is live // after (avoid sharing) pytest --basetemp=/tmp/pytest-run-A
Defensive patterns
Strategy: validation
Validate before calling
lock = get_lock_path(p)
if lock.exists():
# stale; remove only if no live process holds it
lock.unlink() Type guard
def _no_stale_lock(p) -> bool:
return not get_lock_path(p).exists() Try / catch
try:
create_cleanup_lock(p)
except OSError:
# retry once or use a different basetemp
pass Prevention
- Give each concurrent pytest run its own basetemp.
- Clean stale lock files from crashed runs before re-running.
When it happens
Trigger: Two pytest runs concurrently cleaning the same tmp dir tree; a previous crashed pytest leaving a stale lock file; manual creation of a '.lock' file in the tmp root.
Common situations: Stale lock files left by killed pytest processes; parallel CI jobs sharing a basetemp; PID reuse making cleanup_on_exit skip removal.
Related errors
- could not create numbered dir with prefix
- lock path got renamed after successful creation
- 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/a37174143e33f5fe.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/pathlib.py:295
except Exception:
pass
else:
_force_symlink(root, prefix + "current", new_path)
return new_path
else:
raise OSError(
"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:
# forkView on GitHub (pinned to 0d6fbdeffa)