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

  1. Deduplicate declaredEndpoints by (host, port, transport) before submitting; remember scheme/host are lowercased and default ports are inferred (http/ws=80, https/wss=443).
  2. Drop the duplicate entry flagged by the key string in the message, which prints as namespaceId/agentName/protocol/host:port/transport.
  3. 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.
  4. 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

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


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/ce54abaee972ddeb. Report an issue: GitHub.