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

  1. Upgrade api and application together so every Operator constant has a case in LabelSelectorConverter.
  2. If you extend Operator, add the matching case in both LabelSelectorConverter and FieldSelectorConverter in the same change.
  3. 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 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


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/04443435ab95359e. Report an issue: GitHub.