PrefectHQ/fastmcp · error · StateFileError

Could not lock CLI state

Error message

Could not lock CLI state

What it means

StateFileError raised by state_lock when acquiring the cross-process advisory lock fails with an OSError (StateFileError from _restrict_access is re-raised unchanged). The CLI cannot guarantee exclusive access to CLI state, so it aborts rather than risking concurrent corruption.

Solutions

  1. Find and terminate the stale process holding the lock (lsof <state-dir>/.state.lock), then retry
  2. Move FASTMCP_STATE_PATH off network filesystems (NFS/SMB) to a local disk
  3. Raise the open-file limit (ulimit -n) if it is exhausted
  4. Remove a leftover .state.lock only after confirming no CLI process is running
Defensive patterns

Strategy: retry

Validate before calling

import subprocess
result = subprocess.run(["lsof", str(state_dir / ".state.lock")], capture_output=True)
if result.stdout:
    raise RuntimeError("Lock held by another process; terminate it first")

Try / catch

import time

for attempt in range(5):
    try:
        with state_lock(state_dir):
            ...
        break
    except StateFileError:
        if attempt == 4:
            raise
        time.sleep(0.5 * (attempt + 1))

Prevention

When it happens

Trigger: Entering state_lock when lock_path.open('a+b') raises OSError (directory not writable, too many open files) or the platform flock/LockFileEx call fails — e.g. a second process holds an incompatible lock or the filesystem does not support locking.

Common situations: Another fastmcp CLI process already holds the lock (stuck/hung process); state directory on an NFS/SMB share without working advisory locks; ulimit -n too low; antivirus holding the file open on Windows.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/f4874bdbb3fc0563. Report an issue: GitHub.

Appendix: source

Thrown at fastmcp_slim/fastmcp/cli/deploy/state.py:125

        if os.name == "nt":
            import msvcrt

            if lock_path.stat().st_size == 0:
                lock_file.write(b"\0")
                lock_file.flush()
            lock_file.seek(0)
            msvcrt.locking(lock_file.fileno(), msvcrt.LK_LOCK, 1)
        else:
            import fcntl

            fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
    except (OSError, StateFileError) as exc:
        if lock_file is not None:
            with suppress(OSError):
                lock_file.close()
        if isinstance(exc, StateFileError):
            raise
        raise StateFileError("Could not lock CLI state") from exc

    try:
        yield
    finally:
        if os.name == "nt":
            import msvcrt

            with suppress(OSError):
                lock_file.seek(0)
                msvcrt.locking(lock_file.fileno(), msvcrt.LK_UNLCK, 1)
        else:
            import fcntl

            with suppress(OSError):
                fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
        with suppress(OSError):
            lock_file.close()

View on GitHub (pinned to 1f02114297)