apache/iceberg · error · LockException
Lock is not active
Error message
Lock is not active
What it means
MetastoreLock.ensureActive was called before the heartbeat thread was started, so there is no live lock to validate. The LockException signals the caller (usually doCommit during the final check) that the lock is not in an active state.
Source
Thrown at hive-metastore/src/main/java/org/apache/iceberg/hive/MetastoreLock.java:156
@Override
public void lock() throws LockException {
// getting a process-level lock per table to avoid concurrent commit attempts to the same table
// from the same JVM process, which would result in unnecessary HMS lock acquisition requests
acquireJvmLock();
// Getting HMS lock
hmsLockId = Optional.of(acquireLock());
// Starting heartbeat for the HMS lock
heartbeat = new Heartbeat(metaClients, hmsLockId.get(), lockHeartbeatIntervalTime);
heartbeat.schedule(exitingScheduledExecutorService);
}
@Override
public void ensureActive() throws LockException {
if (heartbeat == null) {
throw new LockException("Lock is not active");
}
if (heartbeat.encounteredException != null) {
throw new LockException(
heartbeat.encounteredException,
"Failed to heartbeat for hive lock. %s",
heartbeat.encounteredException.getMessage());
}
if (!heartbeat.active()) {
throw new LockException("Hive lock heartbeat thread not active");
}
}
@Override
public void unlock() {
if (heartbeat != null) {
heartbeat.cancel();
exitingScheduledExecutorService.shutdown();View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure lock() successfully acquired the lock and started the heartbeat before any commit is attempted.
- Do not reuse a MetastoreLock instance after unlock()/close(); acquire a fresh lock per commit.
- Check acquisition logs for earlier failures that left the lock in an uninitialized state.
Example fix
// before MetastoreLock lock = ...; lock.unlock(); lock.ensureActive(); // fails: Lock is not active // after lock.ensureActive(); // validate while held ... doCommit ... lock.unlock(); // only when done
Defensive patterns
Strategy: type-guard
Type guard
boolean lockActive(MetastoreLock lock) {
return lock != null && lockHeartbeatStarted(lock); // heartbeat != null and running
} Try / catch
try {
lock.ensureActive();
commit();
} catch (LockException e) {
// re-acquire lock and retry commit
} Prevention
- Acquire a fresh lock per commit; never reuse after unlock/close.
- Check that lock() succeeded (non-null lockId) before committing.
When it happens
Trigger: Calling lock()/doCommit path when MetastoreLock's heartbeat was never initialized — e.g. lock acquisition path skipped heartbeat start, or ensureActive invoked after unlock.
Common situations: Programming errors in custom subclasses of the lock; using a lock instance after close/unlock; failed lock acquisition leaving heartbeat null.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot call acquireLock twice for %s
- Failed to acquire locks from metastore because the underlyin
- Failed to heartbeat for hive lock. %s
- Hive lock heartbeat thread not active
- Waiting for lock on table %s.%s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/023bb57db87cdb4f.
Report an issue: GitHub.