{"record":{"id":"c89d1ace733384d1","repo":"rustfs/rustfs","slug":"invalid-lock-handle-handle-id","errorCode":null,"errorMessage":"Invalid lock handle: {handle_id}","messagePattern":"Invalid lock handle: (.+?)","errorType":"exception","errorClass":"LockError","httpStatus":null,"severity":"error","filePath":"crates/lock/src/error.rs","lineNumber":51,"sourceCode":"\n    /// Network error\n    #[error(\"Network error: {message}\")]\n    Network {\n        message: String,\n        #[source]\n        source: Box<dyn std::error::Error + Send + Sync>,\n    },\n\n    /// Internal error\n    #[error(\"Internal error: {message}\")]\n    Internal { message: String },\n\n    /// Resource is already locked\n    #[error(\"Resource '{resource}' is already locked by {owner}\")]\n    AlreadyLocked { resource: String, owner: String },\n\n    /// Invalid lock handle\n    #[error(\"Invalid lock handle: {handle_id}\")]\n    InvalidHandle { handle_id: String },\n\n    /// Configuration error\n    #[error(\"Configuration error: {message}\")]\n    Configuration { message: String },\n\n    /// Serialization error\n    #[error(\"Serialization error: {message}\")]\n    Serialization {\n        message: String,\n        #[source]\n        source: Box<dyn std::error::Error + Send + Sync>,\n    },\n\n    /// Deserialization error\n    #[error(\"Deserialization error: {message}\")]\n    Deserialization {\n        message: String,","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/rustfs/rustfs/blob/35af688cd9d41b4346fbe27dcf7250ba72046c1f/crates/lock/src/error.rs#L33-L69","documentation":"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.","triggerScenarios":"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.","commonSituations":"Double-unlock paths in cleanup code; long hold times exceeding lease TTL without refresh; failover invalidating outstanding handles.","solutions":["Drop the stale handle locally and re-acquire the lock if the work must continue","Guard cleanup code so unlock is attempted exactly once per acquisition","Enable/verify lease refresh for holds longer than the TTL so handles stay valid"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_invalid_handle(e: &rustfs_lock::error::LockError) -> bool {\n    matches!(e, rustfs_lock::error::LockError::InvalidHandle { .. })\n}","tryCatchPattern":"match ns.unlock(handle.clone()).await {\n    Err(e) if is_invalid_handle(&e) => { /* already gone: drop local handle, not an error */ }\n    other => other?,\n}","preventionTips":["Attempt unlock exactly once per acquired handle","Refresh leases for holds longer than the TTL","After a restart, re-acquire instead of reusing persisted handle ids"],"tags":["rust","lock","handle","stale-state"],"backgroundTag":"invalid-handle","analyzedSha":"35af688cd9d41b4346fbe27dcf7250ba72046c1f","analyzedAt":"2026-08-20T21:57:04.799Z","contentChangedAt":"2026-08-20T21:57:04.799Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}