apache/dolphinscheduler · error · UnsupportedOperationException

The client is not the lock owner of the lock:

Error message

The client  is not the lock owner of the lock: 

What it means

JdbcRegistryLockManager.releaseJdbcRegistryLock verifies that the clientId releasing the lock matches the clientId recorded in the lock entry's JdbcRegistryLock row. If the local thread holds the lock entry (via LockUtils.getLockOwner) but the given clientId differs from the stored owner, the release is rejected with UnsupportedOperationException. This protects distributed lock state from being released by the wrong client.

Source

Thrown at dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-jdbc/src/main/java/org/apache/dolphinscheduler/plugin/registry/jdbc/server/JdbcRegistryLockManager.java:141

                // The lock is already exist, wait it release.
                continue;
            }
            log.debug("{} acquire the lock {} failed try again", lockOwner, lockKey);
            // acquire failed, wait and try again
            ThreadUtils.sleep(jdbcRegistryProperties.getHeartbeatRefreshInterval().toMillis());
        }
        return false;
    }

    @Override
    public void releaseJdbcRegistryLock(Long clientId, String lockKey) {
        String lockOwner = LockUtils.getLockOwner();
        LockEntry lockEntry = jdbcRegistryLockHolderMap.get(lockKey);
        if (lockEntry == null || !lockOwner.equals(lockEntry.getLockOwner())) {
            return;
        }
        if (!clientId.equals(lockEntry.getJdbcRegistryLock().getClientId())) {
            throw new UnsupportedOperationException(
                    "The client " + clientId + " is not the lock owner of the lock: " + lockKey);
        }
        int newLockCount = lockEntry.lockCount.decrementAndGet();
        if (newLockCount > 0) {
            return;
        }
        if (newLockCount < 0) {
            throw new IllegalMonitorStateException("Jdbc lock count has gone negative for lock: " + lockKey);
        }
        jdbcRegistryLockRepository.deleteById(lockEntry.getJdbcRegistryLock().getId());
        jdbcRegistryLockHolderMap.remove(lockKey);
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class LockEntry {

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Always acquire and release the lock with the same clientId value
  2. Reuse one clientId per process lifetime instead of regenerating it
  3. Guard release calls so they only run on the thread/client that successfully acquired

Example fix

// before
long clientId = System.nanoTime(); // new id per call
registryClient.acquireJdbcRegistryLock(this.clientId, lockKey);
registryClient.releaseJdbcRegistryLock(clientId, lockKey); // wrong client
// after
registryClient.acquireJdbcRegistryLock(this.clientId, lockKey);
registryClient.releaseJdbcRegistryLock(this.clientId, lockKey);
Defensive patterns

Strategy: validation

Validate before calling

if (this.clientId == null) throw new IllegalStateException("Client not connected; cannot release lock " + lockKey);

Try / catch

try { registryClient.releaseJdbcRegistryLock(clientId, lockKey); } catch (UnsupportedOperationException e) { log.warn("Lock {} not owned by client {}", lockKey, clientId); }

Prevention

When it happens

Trigger: Calling releaseJdbcRegistryLock with a clientId different from the one used in acquireJdbcRegistryLock; reusing the same lockKey across services with mismatched client identity; a client reconnecting with a new clientId and trying to release the old lock key.

Common situations: Client ID regenerated after server restart while a stale lock row remains, passing a hard-coded or default clientId to release while acquiring with the real one, thread pools crossing client contexts.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/68e1011b5a1f6dc1. Report an issue: GitHub.