{"record":{"id":"accb801c003eed0c","repo":"alibaba/nacos","slug":"runtime-endpoint-binding-must-be-complete","errorCode":null,"errorMessage":"Runtime Endpoint binding must be complete","messagePattern":"Runtime Endpoint binding must be complete","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java","lineNumber":138,"sourceCode":"                output.writeBoolean(endpoint.getHealthy());\n                writeBindings(output, endpoint.getBindings());\n            }\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Unable to frame Runtime Endpoint projection\", e);\n        }\n        return buffer.toByteArray();\n    }\n    \n    private static List<RuntimeVersionBinding> canonicalBindings(\n        List<RuntimeVersionBinding> bindings) {\n        if (bindings == null || bindings.isEmpty()) {\n            throw new IllegalArgumentException(\"Runtime Endpoint bindings must not be empty\");\n        }\n        List<RuntimeVersionBinding> result = new ArrayList<RuntimeVersionBinding>(bindings);\n        for (RuntimeVersionBinding binding : result) {\n            if (binding == null || binding.getRuntimeVersion() == null\n                || binding.getVersionRange() == null) {\n                throw new IllegalArgumentException(\"Runtime Endpoint binding must be complete\");\n            }\n        }\n        Collections.sort(result, new Comparator<RuntimeVersionBinding>() {\n            \n            @Override\n            public int compare(RuntimeVersionBinding left, RuntimeVersionBinding right) {\n                int comparison = AgentVersionComparator.compare(left.getRuntimeVersion(),\n                    right.getRuntimeVersion());\n                return comparison == 0\n                    ? left.getVersionRange().compareTo(right.getVersionRange()) : comparison;\n            }\n        });\n        return result;\n    }\n    \n    private static void writeBindings(DataOutputStream output,\n        List<RuntimeVersionBinding> bindings) throws IOException {\n        output.writeInt(bindings.size());","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java#L120-L156","documentation":"Each RuntimeVersionBinding on a runtime Endpoint must be fully populated: the binding itself, runtimeVersion, and versionRange must all be non-null. This guard in canonicalBindings iterates every binding and rejects incomplete entries, ensuring the revision frame can sort and hash version bindings deterministically.","triggerScenarios":"Calling RuntimeEndpointRevision.compute with an endpoint whose bindings list contains a RuntimeVersionBinding where getRuntimeVersion() or getVersionRange() is null, or the binding object itself is null.","commonSituations":"A runtime agent registers a binding with only runtimeVersion but no versionRange. An adaptor partially maps binding data. JSON deserialization leaves a field null because it was absent in the payload. A null element slips into the bindings list.","solutions":["Set both binding.setRuntimeVersion(...) and binding.setVersionRange(...) on every binding.","Remove null binding elements from the bindings list before computing the revision.","Ensure the registration payload includes both runtimeVersion and versionRange for every binding."],"exampleFix":"// before — incomplete binding\nRuntimeVersionBinding binding = new RuntimeVersionBinding();\nbinding.setRuntimeVersion(\"1.0.0\");\nbinding.setVersionRange(null); // missing\nendpoint.setBindings(List.of(binding));\nRuntimeEndpointRevision.compute(ns, name, proto, endpoints); // throws\n\n// after — complete binding\nbinding.setVersionRange(\"[1.0,2.0)\");\nendpoint.setBindings(List.of(binding));\nRuntimeEndpointRevision.compute(ns, name, proto, endpoints);","handlingStrategy":"validation","validationCode":"for (RuntimeVersionBinding b : endpoint.getBindings()) {\n    if (b == null || b.getRuntimeVersion() == null || b.getVersionRange() == null) {\n        throw new IllegalArgumentException(\"Incomplete binding on endpoint: \" + endpoint.getUri());\n    }\n}","typeGuard":"boolean allBindingsComplete(List<AgentDiscoveryEndpoint> endpoints) {\n    return endpoints.stream().flatMap(e -> e.getBindings().stream()).allMatch(\n        b -> b != null && b.getRuntimeVersion() != null && b.getVersionRange() != null);\n}","tryCatchPattern":null,"preventionTips":["Always set both runtimeVersion and versionRange on every RuntimeVersionBinding.","Filter out null binding elements before revision computation.","Validate binding completeness client-side before submission."],"tags":["agent","ai-registry","rad-protocol","runtime-endpoint","version-binding"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}