alibaba/nacos · error · IllegalArgumentException
Duplicate declared Endpoint: {key}
Error message
Duplicate declared Endpoint: {key} What it means
Thrown when two entries in a CallInterface's declaredEndpoints share the same EndpointNaturalKey. The natural key is the tuple (namespaceId, agentName, protocol, normalizedHost, effectivePort, transport) computed by EndpointNaturalKey.of after URI canonicalization (lowercased scheme/host, inferred default port, IPv6 normalization). Declared endpoints must be address-distinct within one protocol group, so this is a hard uniqueness constraint, not a warning.
Source
Thrown at api/src/main/java/com/alibaba/nacos/api/ai/utils/AgentModelValidator.java:546
}
}
private static void validateDeclaredEndpoints(String namespaceId, String agentName,
String protocol, List<Endpoint> endpoints) {
if (endpoints == null) {
return;
}
if (endpoints.size() > MAX_DECLARED_ENDPOINTS) {
throw new IllegalArgumentException(
"declaredEndpoints exceeds " + MAX_DECLARED_ENDPOINTS + " items");
}
Set<EndpointNaturalKey> endpointKeys = new HashSet<EndpointNaturalKey>();
for (Endpoint endpoint : endpoints) {
validateEndpoint(endpoint);
EndpointNaturalKey key = EndpointNaturalKey.of(namespaceId, agentName, protocol,
endpoint);
if (!endpointKeys.add(key)) {
throw new IllegalArgumentException("Duplicate declared Endpoint: " + key);
}
}
}
private static void validateRuntimeEndpointSnapshotItem(RuntimeEndpointSnapshot snapshot,
AgentVersion selectedVersion, RuntimeEndpointSnapshotItem item,
Set<EndpointNaturalKey> endpointKeys) {
requireNonNull(item, "runtimeEndpointSnapshot item");
validateEndpoint(item.getEndpoint());
EndpointNaturalKey endpointKey = EndpointNaturalKey.of(snapshot.getNamespaceId(),
snapshot.getAgentName(), snapshot.getProtocol(), item.getEndpoint());
if (!endpointKeys.add(endpointKey)) {
throw new IllegalArgumentException("Duplicate runtime Endpoint: " + endpointKey);
}
List<RuntimeVersionBinding> bindings = item.getBindings();
requireNonNull(bindings, "runtimeEndpointSnapshot.bindings");
if (bindings.isEmpty()) {View on GitHub (pinned to 9b989acdf1)
Solutions
- Deduplicate declaredEndpoints by (host, port, transport) before submitting; remember scheme/host are lowercased and default ports are inferred (http/ws=80, https/wss=443).
- Drop the duplicate entry flagged by the key string in the message, which prints as namespaceId/agentName/protocol/host:port/transport.
- If the two entries legitimately differ only by priority/weight/metadata, they are NOT distinct endpoints — merge them into one Endpoint with the desired routing attributes.
- Use EndpointNaturalKey.of(...) yourself to pre-compute keys and detect collisions before calling the validator.
Example fix
// before
declared.add(uri("grpc://svc:8080"));
declared.add(uri("grpc://svc:8080")); // same natural key -> rejected
// after
declared.add(uri("grpc://svc:8080"));
declared.add(uri("grpc://svc:8081")); // distinct host:port Defensive patterns
Strategy: validation
Validate before calling
import com.alibaba.nacos.api.ai.utils.EndpointNaturalKey;
import java.util.HashSet;
import java.util.Set;
Set<EndpointNaturalKey> seen = new HashSet<>();
for (Endpoint e : callInterface.getDeclaredEndpoints()) {
EndpointNaturalKey k = EndpointNaturalKey.of(namespaceId, agentName, protocol, e);
if (!seen.add(k)) {
throw new IllegalStateException("duplicate declared endpoint: " + k);
}
} Type guard
// Java collision pre-check
static boolean noDeclaredDuplicates(String ns, String name, String proto, List<Endpoint> eps) {
Set<EndpointNaturalKey> s = new HashSet<>();
for (Endpoint e : eps) {
if (!s.add(EndpointNaturalKey.of(ns, name, proto, e))) return false;
}
return true;
} Try / catch
try {
AgentModelValidator.validateAgent(agent);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Duplicate declared Endpoint")) {
// parse the key, dedup the list, retry
} else throw e;
} Prevention
- Remember URI scheme/host are lowercased and default ports are inferred in the natural key.
- priority/weight/metadata do NOT make endpoints distinct.
- Dedup by host:port:transport before submission.
When it happens
Trigger: validateDeclaredEndpoints iterates the declaredEndpoints list, builds an EndpointNaturalKey per entry via EndpointCanonicalizer, and rejects the second entry whose key was already added to the set. Triggered by Agent publish/update through validateAgent, and by any direct call to AgentModelValidator.validateAgent / validateAgentSummary.
Common situations: Two endpoints that look different in the raw URI but canonicalize to the same host:port:transport (e.g. 'http://h:80' vs 'http://h', or 'http://H' vs 'http://h'); a copy-paste that re-lists the same address with different priority/weight/metadata (those fields are NOT part of the natural key); merging endpoint lists from two sources without dedup; trailing-slash or case differences that the canonicalizer collapses.
Related errors
- Duplicate runtime Endpoint: {endpointKey}
- declaredEndpoints exceeds {MAX_DECLARED_ENDPOINTS} items
- Duplicate Runtime Version binding
- Management or declared Endpoint forbids healthy
- 20002
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/ce54abaee972ddeb.
Report an issue: GitHub.