pypi / filelock
filelock
What changed in filelock 4, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-18.
3 breaking3 security1 performance1 behavior and defaults22 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initfilelock 430 changes
Breaking changes 3
On Windows, a mode without group and other bits creates the lock file with an owner-only permission list.
Records are reached through descriptors opened without following symlinks, Windows junctions are refused, and heartbeats verify ownership before rewriting records.
The lock directory and claims directory are created with the lock's mode and the sticky bit; a later acquisition narrows a wider directory it owns.
Security 3
On Windows, a mode without group and other bits now creates the database with an owner-only permission list.
SQLite database access avoids journal, WAL, or shared-memory files placed beside the database by another account; unsafe directories use a private hard link, and unavailable hard links raise
OSErroron Windows.Claims are reached through descriptors opened without following symlinks, Windows junctions are refused, and a coordination directory owned by another account under a sticky parent is refused.
Performance 1
Importing filelock is about twice as fast because lock types other than FileLock load on first use.
Behavior and default changes 1
On Linux and macOS, stale markers change hands in one atomic exchange; on other platforms without one, except Windows, the marker stays in place and waits for
timeoutorbreak_lock().
Fixes and other changes 22
A failed acquire on a relative path whose working directory no longer exists now leaves the lock's hold count unchanged, so a later with lock block can release the lock correctly. The failed call still raises FileNotFoundError.
Signal-handler exceptions while joining the queue no longer block later calls, and release returns after many acquires give up behind a waiter.
A
thread_local=Truelock shared by threads with their own event loops no longer deadlocks when one thread waits while another holds it.Canceling an acquire waiting for another process now stops the wait and raises cancellation instead of waiting for release or raising
Timeout.Async read-write locks associate holds with their task owner, forget holds after a backend release that already let go, and free acquire memory on timeout or cancellation.
Async read-write wrappers stop admitting readers into a level whose release was interrupted.
Release gives back one level so synchronous readers of a shared singleton keep their own holds.
A lookup no longer returns a cached lock whose relative path now resolves to another file, or a lock whose finalizer is running.
A release interrupted by a signal handler no longer leaves the lock dropped, and the lock is reacquired after an interrupted release.
A database schema taking more than a few kilobytes to load raises
ValueErrorrather than running past the acquire timeout.On Windows, acquisition waits for its timeout and raises
Timeout; a fork from another thread no longer waits for an acquire on a busy database.The path resolved when acquisition starts remains in use until the hold ends, avoiding locks or markers being redirected when the process changes directory.
Closing a wrapper ends only holds acquired through that wrapper; wrappers refuse readers joining an ended hold, and closing one wrapper no longer ends another wrapper's nested hold.
Lease markers are no longer removed or displaced while live because of marker replacement, reused inode numbers, time-namespace differences, or stale-break races.
Soft lock markers are no longer removed or displaced while live because of empty marker contents, reused inode numbers, time-namespace differences, unreadable boot IDs, or marker replacement races.
An empty marker is treated as held, preventing contenders from evicting markers belonging to older versions or owners still writing their record.
Read levels are tracked per thread, so release by a thread holding none raises
RuntimeError; after its heartbeat records a lost hold, it refuses new acquires until that hold is released.A commit a whole retention window behind the log is refused, preventing adjacent stalled generations from admitting a second writer; stale checks sample the clock before reading a holder record.
Each concrete subclass now keeps its own singleton cache and construction guard, including after fork.
A non-regular node at a sentinel private-record name raises
SoftFileLockProtocolError.Opening the lock file no longer truncates a file the lock did not create or applies
modeto it; anon_acquiredhook writing holder metadata now truncates the file itself.Fixes StrictSoftFileLock raising SoftFileLockProtocolError on Windows when a contender reads a claim while its owner is finishing the unlink.