alibaba/nacos · error · IllegalArgumentException
Runtime Endpoint healthy must not be null
Error message
Runtime Endpoint healthy must not be null
What it means
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.
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.
Example fix
// before endpoint.setHealthy(null); endpoints.add(endpoint); RuntimeEndpointRevision.compute(ns, name, proto, endpoints); // throws // after endpoint.setHealthy(true); endpoints.add(endpoint); RuntimeEndpointRevision.compute(ns, name, proto, endpoints);
Defensive patterns
Strategy: validation
Validate before calling
for (AgentDiscoveryEndpoint ep : endpoints) {
if (ep.getHealthy() == null) {
throw new IllegalArgumentException("Endpoint healthy is null: " + ep.getUri());
}
} Type guard
boolean allEndpointsHaveHealth(List<AgentDiscoveryEndpoint> endpoints) {
return endpoints.stream().allMatch(e -> e.getHealthy() != null);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Duplicate Runtime Endpoint
- Runtime Endpoint binding must be complete
- Runtime Endpoint bindings must not be empty
- Runtime Endpoint projection exceeds 1000 items
- 20002
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/9b82a88fc6518ef6.
Report an issue: GitHub.
Appendix: source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java:97
static byte[] revisionBytes(String namespaceId, String agentName, String protocol,
List<AgentDiscoveryEndpoint> endpoints) {
AgentValidationUtils.validateNamespaceId(namespaceId);
AgentValidationUtils.validateAgentName(agentName);
AgentValidationUtils.validateProtocol(protocol);
if (endpoints == null) {
throw new IllegalArgumentException("Runtime Endpoint projection must not be null");
}
if (endpoints.size() > MAX_ENDPOINTS) {
throw new IllegalArgumentException(
"Runtime Endpoint projection exceeds " + MAX_ENDPOINTS + " items");
}
Map<EndpointNaturalKey, AgentDiscoveryEndpoint> canonicalEndpoints =
new TreeMap<EndpointNaturalKey, AgentDiscoveryEndpoint>();
for (AgentDiscoveryEndpoint endpoint : endpoints) {
Endpoint canonicalEndpoint = EndpointCanonicalizer.canonicalize(endpoint);
AgentDiscoveryEndpoint canonical = copyEndpoint(canonicalEndpoint);
if (canonical.getHealthy() == null) {
throw new IllegalArgumentException("Runtime Endpoint healthy must not be null");
}
canonical.setBindings(canonicalBindings(endpoint.getBindings()));
EndpointNaturalKey key = EndpointNaturalKey.of(namespaceId, agentName, protocol,
canonical);
if (canonicalEndpoints.put(key, canonical) != null) {
throw new IllegalArgumentException("Duplicate Runtime Endpoint: " + key);
}
}
return frame(canonicalEndpoints);
}
private static byte[] frame(Map<EndpointNaturalKey, AgentDiscoveryEndpoint> endpoints) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (DataOutputStream output = new DataOutputStream(buffer)) {
output.writeInt(endpoints.size());
for (AgentDiscoveryEndpoint endpoint : endpoints.values()) {
writeUtf8(output, endpoint.getUri());
writeUtf8(output, endpoint.getTransport());View on GitHub (pinned to 9b989acdf1)