alibaba/nacos · error · IllegalArgumentException

Runtime Endpoint bindings must not be empty

Error message

Runtime Endpoint bindings must not be empty

What it means

Every runtime Endpoint in a revision projection must carry a non-empty list of RuntimeVersionBindings. This guard in canonicalBindings runs during revision computation, ensuring each endpoint declares which runtime implementation versions and Agent version ranges it can serve.

Source

Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/fingerprint/RuntimeEndpointRevision.java:132

                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());
            }
        } catch (IOException e) {
            throw new IllegalStateException("Unable to frame Runtime Endpoint projection", e);
        }
        return buffer.toByteArray();
    }
    
    private static List<RuntimeVersionBinding> canonicalBindings(
        List<RuntimeVersionBinding> bindings) {
        if (bindings == null || bindings.isEmpty()) {
            throw new IllegalArgumentException("Runtime Endpoint bindings must not be empty");
        }
        List<RuntimeVersionBinding> result = new ArrayList<RuntimeVersionBinding>(bindings);
        for (RuntimeVersionBinding binding : result) {
            if (binding == null || binding.getRuntimeVersion() == null
                || binding.getVersionRange() == null) {
                throw new IllegalArgumentException("Runtime Endpoint binding must be complete");
            }
        }
        Collections.sort(result, new Comparator<RuntimeVersionBinding>() {
            
            @Override
            public int compare(RuntimeVersionBinding left, RuntimeVersionBinding right) {
                int comparison = AgentVersionComparator.compare(left.getRuntimeVersion(),
                    right.getRuntimeVersion());
                return comparison == 0
                    ? left.getVersionRange().compareTo(right.getVersionRange()) : comparison;
            }
        });

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Set endpoint.setBindings(...) with at least one RuntimeVersionBinding before computing the revision.
  2. Ensure each runtime endpoint declares its runtimeVersion and the Agent versionRange it serves.
  3. Default to a single binding covering all versions if the runtime serves a broad range.

Example fix

// before
endpoint.setBindings(null);
// or
endpoint.setBindings(Collections.emptyList());
RuntimeEndpointRevision.compute(ns, name, proto, endpoints); // throws

// after
RuntimeVersionBinding binding = new RuntimeVersionBinding();
binding.setRuntimeVersion("1.0.0");
binding.setVersionRange("[1.0,2.0)");
endpoint.setBindings(List.of(binding));
RuntimeEndpointRevision.compute(ns, name, proto, endpoints);
Defensive patterns

Strategy: validation

Validate before calling

for (AgentDiscoveryEndpoint ep : endpoints) {
    if (ep.getBindings() == null || ep.getBindings().isEmpty()) {
        throw new IllegalArgumentException("Endpoint bindings empty: " + ep.getUri());
    }
}

Type guard

boolean allEndpointsHaveBindings(List<AgentDiscoveryEndpoint> endpoints) {
    return endpoints.stream().allMatch(e -> e.getBindings() != null && !e.getBindings().isEmpty());
}

Prevention

When it happens

Trigger: Calling RuntimeEndpointRevision.compute with an endpoints list where at least one AgentDiscoveryEndpoint has getBindings() returning null or an empty list. The canonicalBindings method at line 129 is invoked for each endpoint during canonicalization.

Common situations: A runtime agent registers endpoints without specifying version bindings. An adaptor maps endpoints but omits the bindings field. JSON deserialization leaves bindings unset because the field was absent in the registration payload.

Related errors


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