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
- Derive state from enabled/healthy instead of setting it independently: !enabled -> DISABLED; !healthy -> UNHEALTHY; otherwise AVAILABLE.
- Recompute and rewrite item.state whenever enabled or healthy changes, before pushing the snapshot.
- If your data source only gives you enabled/healthy, omit state computation and set it from the rule above; never carry a stale state.
- 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
- Never set state independently — derive it from enabled/healthy.
- Centralize the (enabled,healthy)->state rule in one helper used by all push paths.
- Recompute state whenever enabled or healthy changes.
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
- Duplicate runtime Endpoint: {endpointKey}
- Runtime Endpoint bindings must not be empty
- Runtime Version range must be canonical
- versionRange must contain runtimeVersion: {runtimeVersion}
- Snapshot binding does not match selected Version: {selectedV
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/ffe13daf491375e6.
Report an issue: GitHub.