alibaba/nacos · error · IllegalArgumentException
Duplicate Runtime Endpoint: {}
Error message
Duplicate Runtime Endpoint: {} What it means
Within a single runtime Endpoint projection, two endpoints cannot share the same natural key (namespaceId + agentName + protocol + canonical host:port + transport). This guard in revisionBytes detects duplicates after canonicalization and rejects them, ensuring the revision frame is deterministic and unambiguous.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java:103
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());
output.writeInt(endpoint.getPriority());
double weight = endpoint.getWeight() == 0D ? 0D : endpoint.getWeight();
output.writeLong(Double.doubleToLongBits(weight));
writeMetadata(output, endpoint.getMetadata());
output.writeBoolean(endpoint.getHealthy());
writeBindings(output, endpoint.getBindings());View on GitHub (pinned to 9b989acdf1)
Solutions
- Deduplicate endpoints by natural key (host, port, transport) before computing the revision.
- If two instances share the same host:port, use a different transport token to distinguish them.
- Merge duplicate endpoints by combining their metadata, priority, and weight instead of keeping both.
Example fix
// before — two endpoints on the same host:port/transport
endpoints.add(ep1); // grpc://10.0.0.1:8080
endpoints.add(ep2); // grpc://10.0.0.1:8080 (same natural key)
RuntimeEndpointRevision.compute(ns, name, proto, endpoints); // throws
// after — deduplicate by natural key
Map<EndpointNaturalKey, AgentDiscoveryEndpoint> deduped = new LinkedHashMap<>();
for (AgentDiscoveryEndpoint ep : endpoints) {
EndpointNaturalKey key = EndpointNaturalKey.of(ns, name, proto, ep);
deduped.putIfAbsent(key, ep);
}
RuntimeEndpointRevision.compute(ns, name, proto, new ArrayList<>(deduped.values())); Defensive patterns
Strategy: validation
Validate before calling
Set<EndpointNaturalKey> seen = new HashSet<>();
for (AgentDiscoveryEndpoint ep : endpoints) {
if (!seen.add(EndpointNaturalKey.of(ns, name, proto, ep))) {
throw new IllegalArgumentException("Duplicate endpoint: " + ep.getUri());
}
} Type guard
boolean noDuplicateKeys(String ns, String name, String proto, List<AgentDiscoveryEndpoint> endpoints) {
Set<EndpointNaturalKey> seen = new HashSet<>();
for (AgentDiscoveryEndpoint ep : endpoints) {
if (!seen.add(EndpointNaturalKey.of(ns, name, proto, ep))) return false;
}
return true;
} Prevention
- Deduplicate endpoints by natural key (host:port + transport) before revision computation.
- Use distinct transport tokens for instances sharing the same host:port.
- Merge metadata for duplicate endpoints instead of submitting both.
When it happens
Trigger: Calling RuntimeEndpointRevision.compute with an endpoints list containing two AgentDiscoveryEndpoints whose EndpointNaturalKey is identical after URI canonicalization (e.g., same host, port, and transport). Two endpoints that differ only in priority, weight, or metadata but share host:port/transport collide.
Common situations: A load balancer reports the same backend instance twice with different metadata. An auto-registration loop registers an endpoint that is already present. Two agents behind the same host:port with the same transport token but different URIs that canonicalize to the same host:port.
Related errors
- Runtime Endpoint projection exceeds 1000 items
- Runtime Endpoint healthy must not be null
- Runtime Endpoint bindings must not be empty
- Runtime Endpoint binding must be complete
- CONFLICT
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/943d471c7a596123.
Report an issue: GitHub.