{"record":{"id":"17be452bf1231187","repo":"apache/iceberg","slug":"failed-to-unlock","errorCode":null,"errorMessage":"Failed to unlock {}.{}","messagePattern":"Failed to unlock (.+?)\\.(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"hive-metastore/src/main/java/org/apache/iceberg/hive/MetastoreLock.java","lineNumber":426,"sourceCode":"      doUnlock(id);\n    } catch (InterruptedException ie) {\n      if (id != null) {\n        // Interrupted unlock. We try to unlock one more time if we have a lockId\n        try {\n          Thread.interrupted(); // Clear the interrupt status flag for now, so we can retry unlock\n          LOG.warn(\"Interrupted unlock we try one more time {}.{}\", databaseName, tableName, ie);\n          doUnlock(id);\n        } catch (Exception e) {\n          LOG.warn(\"Failed to unlock even on 2nd attempt {}.{}\", databaseName, tableName, e);\n        } finally {\n          Thread.currentThread().interrupt(); // Set back the interrupt status\n        }\n      } else {\n        Thread.currentThread().interrupt(); // Set back the interrupt status\n        LOG.warn(\"Interrupted finding locks to unlock {}.{}\", databaseName, tableName, ie);\n      }\n    } catch (Exception e) {\n      LOG.warn(\"Failed to unlock {}.{}\", databaseName, tableName, e);\n    }\n  }\n\n  private void doUnlock(long lockId) throws TException, InterruptedException {\n    metaClients.run(\n        client -> {\n          client.unlock(lockId);\n          return null;\n        });\n  }\n\n  private void acquireJvmLock() {\n    if (jvmLock != null) {\n      throw new IllegalStateException(\n          String.format(\"Cannot call acquireLock twice for %s\", fullName));\n    }\n\n    jvmLock = commitLockCache.get(fullName, t -> new ReentrantLock(true));","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/hive-metastore/src/main/java/org/apache/iceberg/hive/MetastoreLock.java#L408-L444","documentation":"MetastoreLock.unlock catches any Exception from the unlock flow (lock lookup or doUnlock) and logs this warning with database and table names, then returns. The lock may remain in HMS; unlock never throws to the caller.","triggerScenarios":"Any failure while releasing the Hive lock: HMS connection errors, TException from client.unlock, lookup failures by lockId or agentInfo.","commonSituations":"HMS outages during commit finalization; stale/invalid lock ids after metastore restarts; interrupted threads hitting generic exceptions.","solutions":["Verify HMS availability and inspect metastore server logs for unlock failures","Check for leftover locks with SHOW LOCKS and clear them if orphaned","Retry the commit/operation; ensure lock lifecycle is wrapped in try/finally so unlock always runs","Increase client timeouts if metastore is slow"],"exampleFix":"// before\nlock.unlock(); // exception swallowed silently\n// after\nlock.unlock();\nTasks.foreach(() -> hiveClient.unlock(lockId)) // verify cleanup externally if needed\n    .retry(3).suppressExceptions();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { lock.close(); } catch (Exception e) { /* log and verify HMS lock state manually */ }","preventionTips":["Wrap commit+unlock in try/finally or try-with-resources","Verify HMS health before long commit phases","Reconcile SHOW LOCKS against active jobs after outages"],"tags":["hive","lock","metastore","unlock"],"backgroundTag":"http-request-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}