{"record":{"id":"04443435ab95359e","repo":"halo-dev/halo","slug":"unsupported-operator-044434","errorCode":null,"errorMessage":"Unsupported operator: {}","messagePattern":"Unsupported operator: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java","lineNumber":32,"sourceCode":"    public LabelCondition convert(SelectorCriteria criteria) {\n        switch (criteria.operator()) {\n            case Equals -> {\n                return Queries.labelEqual(criteria.key(), getSingleValue(criteria));\n            }\n            case NotEquals -> {\n                return Queries.labelEqual(criteria.key(), getSingleValue(criteria))\n                        .not();\n            }\n            case NotExist -> {\n                return Queries.labelExists(criteria.key()).not();\n            }\n            case Exist -> {\n                return Queries.labelExists(criteria.key());\n            }\n            case IN -> {\n                return Queries.labelIn(criteria.key(), defaultIfNull(criteria.values(), Set.of()));\n            }\n            default -> throw new IllegalArgumentException(\"Unsupported operator: \" + criteria.operator());\n        }\n    }\n\n    String getSingleValue(SelectorCriteria criteria) {\n        if (CollectionUtils.isEmpty(criteria.values())) {\n            throw new IllegalArgumentException(\"No value present for label key: \" + criteria.key());\n        }\n        return criteria.values().iterator().next();\n    }\n}\n","sourceCodeStart":14,"sourceCodeEnd":43,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java#L14-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (new operator added to enum, no case)\n// default -> throw new IllegalArgumentException(\"Unsupported operator: \" + criteria.operator());\n\n// after\ncase Regex -> { return Queries.labelRegex(criteria.key(), getSingleValue(criteria)); }","handlingStrategy":"try-catch","validationCode":"// Defensive: keep the operator set the label converter actually handles in sync with the enum.\nSet<Operator> handled = EnumSet.of(Operator.Equals, Operator.NotEquals,\n    Operator.NotExist, Operator.Exist, Operator.IN);\nif (!handled.contains(criteria.operator())) {\n    throw new IllegalArgumentException(\"Label converter cannot handle operator \" + criteria.operator());\n}","typeGuard":"boolean labelSupported = switch (criteria.operator()) {\n    case Equals, NotEquals, NotExist, Exist, IN -> true;\n    default -> false;\n};","tryCatchPattern":"try {\n    LabelCondition cond = new LabelSelectorConverter().convert(criteria);\n} catch (IllegalArgumentException e) {\n    // operator unsupported on this Halo version; downgrade or reject\n}","preventionTips":["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."],"tags":["java","selector","label-selector","query","maintenance"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}