{"record":{"id":"9b82a88fc6518ef6","repo":"alibaba/nacos","slug":"runtime-endpoint-healthy-must-not-be-null","errorCode":null,"errorMessage":"Runtime Endpoint healthy must not be null","messagePattern":"Runtime Endpoint healthy must not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java","lineNumber":97,"sourceCode":"    static byte[] revisionBytes(String namespaceId, String agentName, String protocol,\n        List<AgentDiscoveryEndpoint> endpoints) {\n        AgentValidationUtils.validateNamespaceId(namespaceId);\n        AgentValidationUtils.validateAgentName(agentName);\n        AgentValidationUtils.validateProtocol(protocol);\n        if (endpoints == null) {\n            throw new IllegalArgumentException(\"Runtime Endpoint projection must not be null\");\n        }\n        if (endpoints.size() > MAX_ENDPOINTS) {\n            throw new IllegalArgumentException(\n                \"Runtime Endpoint projection exceeds \" + MAX_ENDPOINTS + \" items\");\n        }\n        Map<EndpointNaturalKey, AgentDiscoveryEndpoint> canonicalEndpoints =\n            new TreeMap<EndpointNaturalKey, AgentDiscoveryEndpoint>();\n        for (AgentDiscoveryEndpoint endpoint : endpoints) {\n            Endpoint canonicalEndpoint = EndpointCanonicalizer.canonicalize(endpoint);\n            AgentDiscoveryEndpoint canonical = copyEndpoint(canonicalEndpoint);\n            if (canonical.getHealthy() == null) {\n                throw new IllegalArgumentException(\"Runtime Endpoint healthy must not be null\");\n            }\n            canonical.setBindings(canonicalBindings(endpoint.getBindings()));\n            EndpointNaturalKey key = EndpointNaturalKey.of(namespaceId, agentName, protocol,\n                canonical);\n            if (canonicalEndpoints.put(key, canonical) != null) {\n                throw new IllegalArgumentException(\"Duplicate Runtime Endpoint: \" + key);\n            }\n        }\n        return frame(canonicalEndpoints);\n    }\n    \n    private static byte[] frame(Map<EndpointNaturalKey, AgentDiscoveryEndpoint> endpoints) {\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        try (DataOutputStream output = new DataOutputStream(buffer)) {\n            output.writeInt(endpoints.size());\n            for (AgentDiscoveryEndpoint endpoint : endpoints.values()) {\n                writeUtf8(output, endpoint.getUri());\n                writeUtf8(output, endpoint.getTransport());","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java#L79-L115","documentation":"Each runtime Endpoint in a revision projection must have a non-null healthy flag. This guard in revisionBytes runs after EndpointCanonicalizer produces the canonical copy, ensuring the health state is explicit before it is written into the deterministic revision frame.","triggerScenarios":"Calling RuntimeEndpointRevision.compute with an endpoints list where at least one AgentDiscoveryEndpoint has getHealthy() == null after canonicalization. This happens when a runtime Agent reports endpoints without setting the healthy field.","commonSituations":"An SDK or agent runtime omits the healthy field when reporting endpoints. A protocol adaptor maps endpoint data but forgets to set health. JSON deserialization leaves healthy unset because the field was absent in the payload.","solutions":["Set endpoint.setHealthy(true) or endpoint.setHealthy(false) explicitly on every endpoint before computing the revision.","Ensure the runtime agent registration payload includes the healthy field for each endpoint.","Default healthy to true during adaptor conversion if the source protocol does not provide health."],"exampleFix":"// before\nendpoint.setHealthy(null);\nendpoints.add(endpoint);\nRuntimeEndpointRevision.compute(ns, name, proto, endpoints); // throws\n\n// after\nendpoint.setHealthy(true);\nendpoints.add(endpoint);\nRuntimeEndpointRevision.compute(ns, name, proto, endpoints);","handlingStrategy":"validation","validationCode":"for (AgentDiscoveryEndpoint ep : endpoints) {\n    if (ep.getHealthy() == null) {\n        throw new IllegalArgumentException(\"Endpoint healthy is null: \" + ep.getUri());\n    }\n}","typeGuard":"boolean allEndpointsHaveHealth(List<AgentDiscoveryEndpoint> endpoints) {\n    return endpoints.stream().allMatch(e -> e.getHealthy() != null);\n}","tryCatchPattern":null,"preventionTips":["Always set healthy explicitly on every runtime endpoint — never leave it null.","Default to true during adaptor conversion if the source protocol omits health.","Validate the registration JSON includes a healthy boolean for each endpoint."],"tags":["agent","ai-registry","rad-protocol","runtime-endpoint","health-check"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}