alibaba/nacos · error · IllegalArgumentException

Runtime Endpoint state must be {expected}

Error message

Runtime Endpoint state must be {expected}

What it means

Thrown by validateRuntimeEndpointState when item.state does not equal the state derived from enabled/healthy. The validator computes the expected RuntimeEndpointState deterministically: if enabled is false -> DISABLED; else if healthy is false -> UNHEALTHY; else AVAILABLE. The caller-supplied state must match that derivation exactly; state is treated as a redundant, verifiable field rather than an independent input, so clients cannot claim AVAILABLE for an unhealthy or disabled endpoint.

Source

Thrown at api/src/main/java/com/alibaba/nacos/api/ai/utils/AgentModelValidator.java:610

                "Snapshot binding does not match selected Version: " + selectedVersion);
        }
        String bindingKey = runtimeVersion + "\u0000" + versionRange.getValue();
        if (!bindingKeys.add(bindingKey)) {
            throw new IllegalArgumentException("Duplicate Runtime Version binding");
        }
    }
    
    private static void validateRuntimeEndpointState(RuntimeEndpointSnapshotItem item) {
        RuntimeEndpointState expected;
        if (!item.getEnabled()) {
            expected = RuntimeEndpointState.DISABLED;
        } else if (!item.getHealthy()) {
            expected = RuntimeEndpointState.UNHEALTHY;
        } else {
            expected = RuntimeEndpointState.AVAILABLE;
        }
        if (item.getState() != expected) {
            throw new IllegalArgumentException(
                "Runtime Endpoint state must be " + expected.name());
        }
    }
    
    private static void validateEndpoint(Endpoint endpoint) {
        requireNonNull(endpoint, "Endpoint");
        EndpointCanonicalizer.canonicalize(endpoint);
        if (endpoint.getHealthy() != null) {
            throw new IllegalArgumentException("Management or declared Endpoint forbids healthy");
        }
    }
    
    private static void validateAbsoluteUri(String value, String fieldName) {
        if (value.isEmpty() || codePointLength(value) > MAX_URI_LENGTH) {
            throw new IllegalArgumentException("Invalid " + fieldName + ": " + value);
        }
        try {
            URI uri = new URI(value);

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Derive state from enabled/healthy instead of setting it independently: !enabled -> DISABLED; !healthy -> UNHEALTHY; otherwise AVAILABLE.
  2. Recompute and rewrite item.state whenever enabled or healthy changes, before pushing the snapshot.
  3. If your data source only gives you enabled/healthy, omit state computation and set it from the rule above; never carry a stale state.
  4. Centralize the (enabled,healthy)->state mapping in one helper so all push paths stay consistent.

Example fix

// before
item.setEnabled(false);
item.setHealthy(true);
item.setState(RuntimeEndpointState.AVAILABLE); // mismatch -> rejected
// after
RuntimeEndpointState s = !item.getEnabled() ? RuntimeEndpointState.DISABLED
    : !item.getHealthy() ? RuntimeEndpointState.UNHEALTHY
    : RuntimeEndpointState.AVAILABLE;
item.setState(s);
Defensive patterns

Strategy: validation

Validate before calling

import com.alibaba.nacos.api.ai.model.agent.RuntimeEndpointState;

for (RuntimeEndpointSnapshotItem it : snapshot.getItems()) {
    RuntimeEndpointState expected = !it.getEnabled() ? RuntimeEndpointState.DISABLED
        : !it.getHealthy() ? RuntimeEndpointState.UNHEALTHY
        : RuntimeEndpointState.AVAILABLE;
    if (it.getState() != expected) {
        it.setState(expected); // self-heal before push
    }
}

Type guard

static boolean stateConsistent(RuntimeEndpointSnapshotItem it) {
    RuntimeEndpointState expected = !it.getEnabled() ? RuntimeEndpointState.DISABLED
        : !it.getHealthy() ? RuntimeEndpointState.UNHEALTHY
        : RuntimeEndpointState.AVAILABLE;
    return it.getState() == expected;
}

Try / catch

try {
    AgentModelValidator.validateRuntimeEndpointSnapshot(snapshot);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Runtime Endpoint state must be")) {
        // recompute state from enabled/healthy and retry
    } else throw e;
}

Prevention

When it happens

Trigger: A RuntimeEndpointSnapshotItem where (enabled, healthy, state) are inconsistent. Examples: enabled=false, healthy=true, state=AVAILABLE -> expected DISABLED, rejected. enabled=true, healthy=false, state=AVAILABLE -> expected UNHEALTHY, rejected. enabled=true, healthy=true, state=DISABLED -> expected AVAILABLE, rejected. Reached at the tail of validateRuntimeEndpointSnapshotItem.

Common situations: Health-check outputting a new healthy=false but the state field left at AVAILABLE from a previous serialization; toggling enabled without recomputing state; an aggregator that copies state from one source and enabled/healthy from another; deserializing a stale snapshot after a health flip.

Related errors


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