halo-dev/halo · error · IllegalArgumentException
Unsupported operator: {}
Error message
Unsupported operator: {} What it means
Thrown by LabelSelectorConverter.convert when the SelectorCriteria operator is not Equals, NotEquals, NotExist, Exist, or IN. With the current Operator enum all five constants are handled, so the default branch is a defensive guard against a future operator added to the enum without a matching case here. It signals the two converters drifted out of sync after an enum extension.
Source
Thrown at api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java:32
public LabelCondition convert(SelectorCriteria criteria) {
switch (criteria.operator()) {
case Equals -> {
return Queries.labelEqual(criteria.key(), getSingleValue(criteria));
}
case NotEquals -> {
return Queries.labelEqual(criteria.key(), getSingleValue(criteria))
.not();
}
case NotExist -> {
return Queries.labelExists(criteria.key()).not();
}
case Exist -> {
return Queries.labelExists(criteria.key());
}
case IN -> {
return Queries.labelIn(criteria.key(), defaultIfNull(criteria.values(), Set.of()));
}
default -> throw new IllegalArgumentException("Unsupported operator: " + criteria.operator());
}
}
String getSingleValue(SelectorCriteria criteria) {
if (CollectionUtils.isEmpty(criteria.values())) {
throw new IllegalArgumentException("No value present for label key: " + criteria.key());
}
return criteria.values().iterator().next();
}
}
View on GitHub (pinned to d2f5165f9c)
Solutions
- Upgrade api and application together so every Operator constant has a case in LabelSelectorConverter.
- If you extend Operator, add the matching case in both LabelSelectorConverter and FieldSelectorConverter in the same change.
- Avoid constructing SelectorCriteria with operators outside the published enum.
Example fix
// before (new operator added to enum, no case)
// default -> throw new IllegalArgumentException("Unsupported operator: " + criteria.operator());
// after
case Regex -> { return Queries.labelRegex(criteria.key(), getSingleValue(criteria)); } Defensive patterns
Strategy: try-catch
Validate before calling
// Defensive: keep the operator set the label converter actually handles in sync with the enum.
Set<Operator> handled = EnumSet.of(Operator.Equals, Operator.NotEquals,
Operator.NotExist, Operator.Exist, Operator.IN);
if (!handled.contains(criteria.operator())) {
throw new IllegalArgumentException("Label converter cannot handle operator " + criteria.operator());
} Type guard
boolean labelSupported = switch (criteria.operator()) {
case Equals, NotEquals, NotExist, Exist, IN -> true;
default -> false;
}; Try / catch
try {
LabelCondition cond = new LabelSelectorConverter().convert(criteria);
} catch (IllegalArgumentException e) {
// operator unsupported on this Halo version; downgrade or reject
} Prevention
- When extending the Operator enum, add cases to both converters in the same commit.
- Upgrade api and application together after any Operator change.
- Never inject operators outside the published enum via custom converters.
When it happens
Trigger: Reachable only if a new Operator constant is added to the enum and a SelectorCriteria carrying it reaches the label converter before a case is added. Not reachable with Equals/IN/NotEquals/NotExist/Exist.
Common situations: Upgrading Halo/api introduces a new Operator (e.g. Contains, Regex) and the application module lags behind; a custom Converter pipeline injects an operator outside the enum contract.
Related errors
- No value present for label key: {}
- Unsupported operator: {}
- No value present for label key: {}
- No such thumbnail size: {}
- Unexpected APIVersion string: {}
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/04443435ab95359e.
Report an issue: GitHub.