{"record":{"id":"41e84d38d270afb0","repo":"MyCATApache/Mycat-Server","slug":"e-41e84d","errorCode":null,"errorMessage":"${e}","messagePattern":"\\$\\{e\\}","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/migrate/SwitchCommitListener.java","lineNumber":344,"sourceCode":"            byte[] ruleData = zk.getData().forPath(rulePath);\n            Properties prop = new Properties();\n            prop.load(new ByteArrayInputStream(ruleData));\n            for (MigrateTask migrateTask : allTaskList) {\n                modifyRuleData(prop, migrateTask, allNewDataNodes);\n            }\n            ByteArrayOutputStream out = new ByteArrayOutputStream();\n            prop.store(out, \"WARNING   !!!Please do not modify or delete this file!!!\");\n            if (transactionFinal == null) {\n                transactionFinal = ZKUtils.getConnection().inTransaction().setData().forPath(rulePath, out.toByteArray()).and();\n            } else {\n                transactionFinal.setData().forPath(rulePath, out.toByteArray());\n            }\n        } finally {\n            try {\n                if (ruleDataLock != null)\n                    ruleDataLock.release();\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return transactionFinal;\n    }\n\n    private void modifyRuleData(Properties prop, MigrateTask task, List<String> allNewDataNodes) {\n        int fromIndex = -1;\n        int toIndex = -1;\n        List<String> dataNodes = allNewDataNodes;\n        for (int i = 0; i < dataNodes.size(); i++) {\n            String dataNode = dataNodes.get(i);\n            if (dataNode.equalsIgnoreCase(task.getFrom())) {\n                fromIndex = i;\n            } else if (dataNode.equalsIgnoreCase(task.getTo())) {\n                toIndex = i;\n            }\n        }\n        String from = prop.getProperty(String.valueOf(fromIndex));","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/migrate/SwitchCommitListener.java#L326-L362","documentation":"In modifyRuleData's finally block, releasing the ZK distributed lock (ruleDataLock.release()) can itself throw (lock already released, session expired, connection lost). That exception is wrapped in a RuntimeException from the finally block, masking the method's normal result. This occurs while updating the rule data during switch commit.","triggerScenarios":"ZooKeeper session expired or closed before release(); release() called on an already-released InterProcessMutex; ZK ensemble unreachable at commit time.","commonSituations":"Long-running rule modification exceeding the ZK session timeout; concurrent switch attempts double-releasing the lock; ZK network blip exactly during commit.","solutions":["Check the 'Caused by' KeeperException: if session expired, verify ZK connectivity and retry the switch commit.","Ensure release() is only called by the lock owner and not twice (guard with a flag or tryAcquire result).","Increase ZK session timeout if rule modification runs long.","Wrap release in a second try/catch that logs instead of throwing, so cleanup failures don't mask the commit result."],"exampleFix":"// before\n} catch (Exception e) {\n    throw new RuntimeException(e);\n}\n// after\n} catch (Exception e) {\n    log.warn(\"Failed to release ruleDataLock\", e); // do not mask commit result\n}","handlingStrategy":"try-catch","validationCode":"// confirm ZK session alive before starting rule modification\nif (client.getState() != CuratorFrameworkState.STARTED || !isSessionAlive(client)) {\n    throw new IllegalStateException(\"ZK session not healthy for lock use\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ruleDataLock.acquire();\n    modifyRuleData(prop, task, nodes);\n} catch (Exception e) {\n    // real failure handling\n} finally {\n    try { ruleDataLock.release(); } catch (Exception rel) { log.warn(\"lock release failed\", rel); }\n}","preventionTips":["Always release the lock in its own try/catch so cleanup never masks the result","Keep ZK session timeout well above rule-modification duration","Only release a lock you actually acquired","Retry switch commit on session-expired release failures after reconnect"],"tags":["zookeeper","distributed-lock","curator","cleanup"],"backgroundTag":"internal-invariant-violation","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}