filelock breaking changes
Every breaking API change we have recorded in filelock on PyPI: 76 breaking changes in 20 versions. Below are its newest 6 versions, removals and renames first, each with its source.
Newest change October 17, 2026

On this page
4.2.1
- Removed
filelock.ReadWriteLock.__del__
ReadWriteLock.__del__ was removed in filelock 4.2.1 pypi.org - Behavior changed
AsyncReadWriteLock
Holds are recorded under a task owner, so synchronous code on the executor thread can no longer re-enter or release a hold taken by an async task. github.com - Behavior changed
AsyncSoftReadWriteLock.release
Each release now gives back one level rather than the whole hold, so callers that expected a full release must release once per acquire. github.com - Behavior changed
ReadWriteLock
Where an account other than the locking account can change names in the database directory and hard links are unavailable, the lock now raises OSError. Keep the database in a directory other accounts cannot write. github.com - Behavior changed
SoftReadWriteLock.release
Read levels are now tracked per thread, so calling release() from a thread that holds none raises RuntimeError. Code that released from another thread must be changed to release from the thread that acquired. github.com - Behavior changed
StrictSoftFileLock
Under a sticky parent such as /tmp the lock now refuses a coordination directory owned by another account. Leftover directories of other accounts must be removed by hand. github.com - Behavior changed
UnixFileLock
The lock no longer truncates a lock file it did not create and no longer applies mode to it. Code that relied on truncation or mode for such files must set them itself. github.com - Signature changed
filelock.LeaseCompromise.__init__
Was def __init__(self, lock_file: str, token: str, reason: CompromiseReason, error: OSError | None = None) -> None; now def __init__(self, lock_file: str, token: str, reason: CompromiseReason, error: Exception | None = None) -> None. pypi.org - Signature changed
filelock.LeaseCompromise.error
Was error: OSError | None; now error: Exception | None. pypi.org
4.1.1
- Behavior changed
To avoid a macOS kernel panic, SQLite is opened through a hard link. The database directory must be writable and support hard links, and alias creation failure raises OSError. github.com
4.1.0
- Behavior changed
BaseAsyncFileLock
When the executor shuts down with a call still queued, BaseAsyncFileLock now raises RuntimeError instead of CancelledError. Code catching CancelledError must catch RuntimeError. github.com - Behavior changed
BaseFileLock
Passing a bool or string timeout, an out-of-range mode, or a non-bool blocking value to BaseFileLock now fails, and unknown options on a singleton cache hit are rejected. Pass numeric seconds and valid options. github.com - Behavior changed
ReadWriteLock
ReadWriteLock and SoftReadWriteLock options given in seconds now refuse bool or string values that were previously accepted. Pass a number. github.com - Behavior changed
ReadWriteLock.release
Calling ReadWriteLock.release() from a thread holding no read level now raises RuntimeError instead of silently ending another thread's read lock. github.com - Behavior changed
SoftFileLock
SoftFileLock now applies an explicit mode past the umask, as UnixFileLock already does, so created marker file permissions can differ from before. github.com - Behavior changed
SoftFileLockLifetimeWarning
SoftFileLockLifetimeWarning now derives from FutureWarning, so code that filters or catches DeprecationWarning for it will no longer match. github.com - Behavior changed
SoftReadWriteLock.close
An acquire still waiting in another thread when SoftReadWriteLock.close() runs now raises RuntimeError instead of taking the lock on the closed instance. github.com - Signature changed
filelock.AcquireReturnProxy
Was class AcquireReturnProxy; now class AcquireReturnProxy(Generic[_LockT]). pypi.org - Signature changed
filelock.AcquireReturnProxy.__enter__
Was def __enter__(self) -> BaseFileLock | ReadWriteLock | SoftReadWriteLock; now def __enter__(self) -> _LockT. pypi.org - Signature changed
filelock.AcquireReturnProxy.__init__
Was def __init__(self, lock: BaseFileLock | ReadWriteLock | SoftReadWriteLock) -> None; now def __init__(self, lock: _LockT) -> None. pypi.org
And 4 more in this version.
4.0.10
- Behavior changed
AsyncFileLock
Reusing a singleton AsyncFileLock with another loop, executor or run_in_executor now raises ValueError instead of returning the lock with its original options. Code that reuses it with changed options must be updated. github.com - Behavior changed
SoftFileLease
Reusing a singleton SoftFileLease with another lease_duration, heartbeat_interval or on_compromise now raises ValueError instead of returning the lease with its original options. Code that reuses it with changed options must be updated. github.com - Signature changed
filelock.SoftFileLease.__init__
Was def __init__(self, lock_file: str | os.PathLike[str], *, lease_duration: float = 30.0, heartbeat_interval: float | None = None, on_compromise: Callable[[LeaseCompromise], None] | None = None, **kwargs: Unpack[LockOptions]) -> None; now... pypi.org
4.0.9
- Behavior changed
AsyncReadWriteLock
AsyncReadWriteLock no longer follows a symlink at the database path and refuses it instead. Code that relied on a symlinked lock database path must point the lock at a real file. github.com - Behavior changed
ReadWriteLock
ReadWriteLock no longer follows a symlink at the database path and refuses it instead. Code that relied on a symlinked lock database path must point the lock at a real file. github.com
4.0.8
- Behavior changed
ReadWriteLock.release
ReadWriteLock.release() called from a thread that does not hold the write lock now raises RuntimeError instead of silently releasing the holder's lock. Code that relied on the old silent behavior must be changed. github.com - Behavior changed
SoftReadWriteLock.release
SoftReadWriteLock.release() called from a thread that does not hold the write lock now raises RuntimeError instead of silently releasing the holder's lock. Code that relied on the old silent behavior must be changed. github.com
Check your code
These are the changes. To see which of them reach your code, scan a public repository, or have your coding agent call check_code with your manifest or lockfile over MCP. The API reads every change in every version, not only the newest. On Team and up, a fix pull request opens for the changes that reach a connected repository. Nothing merges or deploys.

Put your code on continuous management.
Scan a public repository now, or give your agent one line.
See how out of date your code is.
Tell your agent what changed since it was trained.
claude mcp add --transport http since https://api.since.dev/mcp