{"record":{"id":"2a5c6d45161838c2","repo":"apache/dolphinscheduler","slug":"etcd-lock-count-has-gone-negative-for-lock","errorCode":null,"errorMessage":"Etcd lock count has gone negative for lock: ","messagePattern":"Etcd lock count has gone negative for lock: ","errorType":"exception","errorClass":"IllegalMonitorStateException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-etcd/src/main/java/org/apache/dolphinscheduler/plugin/registry/etcd/EtcdRegistry.java","lineNumber":396,"sourceCode":"     * release the lock by revoking the leaseId\n     */\n    @Override\n    public boolean releaseLock(String key) {\n        try {\n            Map<String, LockEntry> lockEntryMap = threadLocalLockMap.get();\n            if (lockEntryMap == null) {\n                return true;\n            }\n            LockEntry lockEntry = lockEntryMap.get(key);\n            if (lockEntry == null) {\n                return true;\n            }\n            int newLockCount = lockEntry.lockCount.decrementAndGet();\n            if (newLockCount > 0) {\n                return true;\n            }\n            if (newLockCount < 0) {\n                throw new IllegalMonitorStateException(\"Etcd lock count has gone negative for lock: \" + key);\n            }\n            client.getLeaseClient().revoke(lockEntry.leaseId);\n            lockEntryMap.remove(key);\n            if (lockEntryMap.isEmpty()) {\n                threadLocalLockMap.remove();\n            }\n        } catch (Exception e) {\n            throw new RegistryException(\"etcd release lock error, lockKey: \" + key, e);\n        }\n        return true;\n    }\n\n    @Override\n    public void close() throws IOException {\n        // When the client closes, the watch also closes.\n        client.close();\n    }\n","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-etcd/src/main/java/org/apache/dolphinscheduler/plugin/registry/etcd/EtcdRegistry.java#L378-L414","documentation":"Thrown in EtcdRegistry.releaseLock when the per-thread re-entrant lock count for the key drops below zero: the code is releasing a lock more times than it acquired it (unbalanced unlock), or the LockEntry state was corrupted. It signals a caller-side lock-protocol violation rather than an etcd failure.","triggerScenarios":"Thrown at dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-etcd/src/main/java/org/apache/dolphinscheduler/plugin/registry/etcd/EtcdRegistry.java:396 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Audit callers to ensure every releaseLock is paired with exactly one successful acquireLock on the same thread","Avoid releasing locks in finally blocks when acquire may have failed","Check for double-release paths (e.g. nested try/finally both calling releaseLock)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}