{"record":{"id":"116a90c6c50626c2","repo":"alibaba/nacos","slug":"duplicate-callinterface-protocol-callinterface-p","errorCode":null,"errorMessage":"Duplicate CallInterface protocol: {callInterface.protocol}","messagePattern":"Duplicate CallInterface protocol: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/com/alibaba/nacos/api/ai/utils/AgentModelValidator.java","lineNumber":511,"sourceCode":"            AgentValidationUtils.validateProtocol(protocol);\n            if (!uniqueProtocols.add(protocol)) {\n                throw new IllegalArgumentException(\"Duplicate protocol: \" + protocol);\n            }\n        }\n    }\n    \n    private static void validateCallInterfaces(String namespaceId, String agentName,\n        List<AgentCallInterface> callInterfaces) {\n        requireNonNull(callInterfaces, \"callInterfaces\");\n        if (callInterfaces.isEmpty() || callInterfaces.size() > MAX_CALL_INTERFACES) {\n            throw new IllegalArgumentException(\n                \"callInterfaces must contain 1 to \" + MAX_CALL_INTERFACES + \" items\");\n        }\n        Set<String> protocols = new HashSet<String>();\n        for (AgentCallInterface callInterface : callInterfaces) {\n            validateCallInterface(namespaceId, agentName, callInterface);\n            if (!protocols.add(callInterface.getProtocol())) {\n                throw new IllegalArgumentException(\n                    \"Duplicate CallInterface protocol: \" + callInterface.getProtocol());\n            }\n        }\n    }\n    \n    private static void validateEndpointSourceOrder(List<EndpointSource> sourceOrder) {\n        requireNonNull(sourceOrder, \"endpointSourceOrder\");\n        if (sourceOrder.isEmpty() || sourceOrder.size() > EndpointSource.values().length) {\n            throw new IllegalArgumentException(\"endpointSourceOrder must contain 1 or 2 sources\");\n        }\n        Set<EndpointSource> uniqueSources = new HashSet<EndpointSource>();\n        for (EndpointSource source : sourceOrder) {\n            requireNonNull(source, \"endpointSourceOrder item\");\n            if (!uniqueSources.add(source)) {\n                throw new IllegalArgumentException(\"Duplicate Endpoint source: \" + source);\n            }\n        }\n    }","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/api/src/main/java/com/alibaba/nacos/api/ai/utils/AgentModelValidator.java#L493-L529","documentation":"Thrown by validateCallInterfaces when two CallInterface entries in the same Version share the same protocol. Each protocol must map to exactly one CallInterface within a Version, so the call target is unambiguous. The validator accumulates protocols in a Set and rejects the second occurrence.","triggerScenarios":"A Version with two CallInterface entries both having protocol = \"mcp\" (e.g. one for declared endpoints and one duplicated by mistake). Copy-pasting a CallInterface and changing only its endpoints but not its protocol.","commonSituations":"Cloning a CallInterface to add a second endpoint set without giving it a distinct protocol; merging interface lists from two sources that both define an MCP interface.","solutions":["Give each CallInterface in a Version a distinct protocol value.","If two interfaces share a protocol, merge them into one CallInterface with combined declared endpoints / endpoint source order.","Deduplicate by protocol before submission."],"exampleFix":"// before\nci1.setProtocol(\"mcp\"); ci2.setProtocol(\"mcp\"); detail.setCallInterfaces(List.of(ci1, ci2));\n// after\nci1.setProtocol(\"mcp\"); ci2.setProtocol(\"a2a\"); detail.setCallInterfaces(List.of(ci1, ci2));","handlingStrategy":"validation","validationCode":"static void checkCallInterfaceProtocolsUnique(List<AgentCallInterface> cis) {\n    Set<String> seen = new HashSet<>();\n    for (var ci : cis) {\n        if (!seen.add(ci.getProtocol())) {\n            throw new IllegalArgumentException(\n                \"Duplicate CallInterface protocol: \" + ci.getProtocol());\n        }\n    }\n}","typeGuard":"static boolean callInterfaceProtocolsUnique(List<AgentCallInterface> cis) {\n    long unique = cis.stream().map(AgentCallInterface::getProtocol).distinct().count();\n    return unique == cis.size();\n}","tryCatchPattern":"try {\n    AgentModelValidator.validateVersionDetail(detail);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Duplicate CallInterface protocol\")) {\n        // merge interfaces sharing a protocol, or assign distinct protocols\n    }\n}","preventionTips":["Give each CallInterface in a Version a distinct protocol.","Merge interfaces that differ only by endpoints into one.","Deduplicate by protocol before submission."],"tags":["ai-agent","validation","call-interface","uniqueness","illegal-argument"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}