rustfs/rustfs · error · LockError

Invalid lock handle: {handle_id}

Error message

Invalid lock handle: {handle_id}

What it means

A lock operation referenced a handle that the lock service does not recognize (handle id included). Locks are manipulated through handles issued at acquisition; this error means the handle is unknown — typically expired, already released, or evicted by the service.

Source

Thrown at crates/lock/src/error.rs:51

    /// Network error
    #[error("Network error: {message}")]
    Network {
        message: String,
        #[source]
        source: Box<dyn std::error::Error + Send + Sync>,
    },

    /// Internal error
    #[error("Internal error: {message}")]
    Internal { message: String },

    /// Resource is already locked
    #[error("Resource '{resource}' is already locked by {owner}")]
    AlreadyLocked { resource: String, owner: String },

    /// Invalid lock handle
    #[error("Invalid lock handle: {handle_id}")]
    InvalidHandle { handle_id: String },

    /// Configuration error
    #[error("Configuration error: {message}")]
    Configuration { message: String },

    /// Serialization error
    #[error("Serialization error: {message}")]
    Serialization {
        message: String,
        #[source]
        source: Box<dyn std::error::Error + Send + Sync>,
    },

    /// Deserialization error
    #[error("Deserialization error: {message}")]
    Deserialization {
        message: String,

View on GitHub (pinned to 35af688cd9)

Solutions

  1. Drop the stale handle locally and re-acquire the lock if the work must continue
  2. Guard cleanup code so unlock is attempted exactly once per acquisition
  3. Enable/verify lease refresh for holds longer than the TTL so handles stay valid
Defensive patterns

Strategy: try-catch

Type guard

fn is_invalid_handle(e: &rustfs_lock::error::LockError) -> bool {
    matches!(e, rustfs_lock::error::LockError::InvalidHandle { .. })
}

Try / catch

match ns.unlock(handle.clone()).await {
    Err(e) if is_invalid_handle(&e) => { /* already gone: drop local handle, not an error */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling unlock/refresh with a handle after the lock was already released; the lease expired and the service dropped the handle; process restarted and reused a persisted handle id that no longer exists.

Common situations: Double-unlock paths in cleanup code; long hold times exceeding lease TTL without refresh; failover invalidating outstanding handles.

Related errors


AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20). Data as JSON: /api/errors/c89d1ace733384d1. Report an issue: GitHub.