{"record":{"id":"a744503034e16b51","repo":"alibaba/canal","slug":"error","errorCode":null,"errorMessage":"节点信息已存在","messagePattern":"节点信息已存在","errorType":"validation","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java","lineNumber":44,"sourceCode":"import com.alibaba.otter.canal.protocol.SecurityUtil;\n\n/**\n * 节点信息业务层\n *\n * @author rewerma 2019-07-13 下午05:12:16\n * @version 1.0.0\n */\n@Service\npublic class NodeServerServiceImpl implements NodeServerService {\n\n    public void save(NodeServer nodeServer) {\n        int cnt = NodeServer.find.query()\n            .where()\n            .eq(\"ip\", nodeServer.getIp())\n            .eq(\"adminPort\", nodeServer.getAdminPort())\n            .findCount();\n        if (cnt > 0) {\n            throw new ServiceException(\"节点信息已存在\");\n        }\n\n        nodeServer.save();\n\n        if (nodeServer.getClusterId() == null) { // 单机模式\n            CanalConfig canalConfig = new CanalConfig();\n            canalConfig.setServerId(nodeServer.getId());\n            String configTmp = TemplateConfigLoader.loadCanalConfig();\n            canalConfig.setContent(configTmp);\n            try {\n                String contentMd5 = SecurityUtil.md5String(canalConfig.getContent());\n                canalConfig.setContentMd5(contentMd5);\n            } catch (NoSuchAlgorithmException e) {\n            }\n            canalConfig.save();\n        }\n    }\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java#L26-L62","documentation":"Thrown by NodeServerServiceImpl.save() when a NodeServer with the same ip AND adminPort already exists. The duplicate-check query counts matching rows and refuses the insert.","triggerScenarios":"POST/register a NodeServer whose (ip, adminPort) pair already exists in node_server. The findCount() > 0 guard throws 'node info already exists'.","commonSituations":"Re-registering a server that was not deleted; double-submit in the UI; HA pair both registered with the same admin port by mistake; stale record after a server re-provision.","solutions":["Delete the existing NodeServer record (or update it) before re-adding.","Use a distinct adminPort for the new server if it is genuinely a different node.","Deduplicate on the client/UI to prevent double-submit.","Query SELECT * FROM node_server WHERE ip=? AND admin_port=? to locate the conflicting record."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"int cnt = NodeServer.find.query().where().eq(\"ip\", ip).eq(\"adminPort\", adminPort).findCount();\nif (cnt > 0) {\n    throw new IllegalStateException(\"NodeServer \" + ip + \":\" + adminPort + \" already exists\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Query for an existing (ip, adminPort) before registering a new node.","Update existing records instead of re-inserting.","Add UI duplicate-submit protection."],"tags":["canal-admin","duplicate","node-server","validation"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}