{"record":{"id":"997b00a917dbe41e","repo":"theonedev/onedev","slug":"unexpected-operator-997b00","errorCode":null,"errorMessage":"Unexpected operator ","messagePattern":"Unexpected operator ","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/search/entity/issue/IssueQuery.java","lineNumber":492,"sourceCode":"\t\t\t\t\t\t\t\t\t\t\t\tcriterias.add(new IntegerFieldCriteria(fieldName, getIntValue(value), operator));\n\t\t\t\t\t\t\t\t\t\t\t} else if (field instanceof FloatField) {\n\t\t\t\t\t\t\t\t\t\t\t\tcriterias.add(new FloatFieldCriteria(fieldName, getFloatValue(value), operator));\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\tlong ordinal;\n\t\t\t\t\t\t\t\t\t\t\t\tif (validate)\n\t\t\t\t\t\t\t\t\t\t\t\t\tordinal = getValueOrdinal((ChoiceField) field, value);\n\t\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t\t\tordinal = 0;\n\t\t\t\t\t\t\t\t\t\t\t\tcriterias.add(new ChoiceFieldCriteria(fieldName, value, ordinal, operator, false));\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase IsBefore:\n\t\t\t\t\t\t\t\tcase IsAfter:\n\t\t\t\t\t\t\t\t\tcriterias.add(new StateCriteria(value, operator));\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tthrow new ExplicitException(\"Unexpected operator \" + getRuleName(operator));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn operator==IsNot? Criteria.andCriterias(criterias): Criteria.orCriterias(criterias);\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Criteria<Issue> visitOrCriteria(OrCriteriaContext ctx) {\n\t\t\t\t\t\tList<Criteria<Issue>> childCriterias = new ArrayList<>();\n\t\t\t\t\t\tfor (CriteriaContext childCtx : ctx.criteria())\n\t\t\t\t\t\t\tchildCriterias.add(visit(childCtx));\n\t\t\t\t\t\treturn new OrCriteria<>(childCriterias);\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Criteria<Issue> visitAndCriteria(AndCriteriaContext ctx) {\n\t\t\t\t\t\tList<Criteria<Issue>> childCriterias = new ArrayList<>();\n\t\t\t\t\t\tfor (CriteriaContext childCtx : ctx.criteria())\n\t\t\t\t\t\t\tchildCriterias.add(visit(childCtx));","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/search/entity/issue/IssueQuery.java#L474-L510","documentation":"Inside visitFieldOperatorValueCriteria, when the parser reduces multiple values of a field-operator-value criteria (e.g. \"State is x or y\"), it maps each operator to a criteria type; Is/IsNot and IsBefore/IsAfter are the only operators handled. Any other operator reaching this switch (an internal grammar/parser mismatch) throws this ExplicitException including the grammar rule name of the unexpected operator. Unlike the 'not supported here' errors, this usually indicates a bug or a field/operator combination the switch does not cover rather than a user mistake.","triggerScenarios":"Parsing a multi-value field criteria like \"<field> is/is not/is before/is after v1, v2\" where the operator token falls through to the default branch, i.e. an operator other than Is/IsNot/IsBefore/IsAfter reaches this code path.","commonSituations":"A custom/modified grammar or new operator added to IssueQuery.g4 without updating this switch; unexpected operator tokens produced by unusual query syntax; version skew where a saved query uses an operator the local parser switch doesn't map.","solutions":["Rewrite the query to use only \"is\"/\"is not\" (or is before/is after for state values) with multiple values, e.g. \"State is Open, Closed\".","Report/fix the parser switch in IssueQuery.visitFieldOperatorValueCriteria to handle the operator for that field.","Catch ExplicitException around IssueQuery.parse and log the operator rule name to diagnose which operator slipped through."],"exampleFix":"// before\nIssueQuery.parse(project, \"State is not before Open\", option, true); // unsupported combo\n// after\nIssueQuery.parse(project, \"State is not Open\", option, true);","handlingStrategy":"try-catch","validationCode":"// restrict multi-value field criteria to supported operators\nSet<String> supported = Set.of(\"is\", \"is not\", \"is before\", \"is after\");\n// pre-scan query tokens; reject other operators combined with value lists","typeGuard":null,"tryCatchPattern":"try {\n    IssueQuery.parse(project, queryString, option, true);\n} catch (ExplicitException e) {\n    if (e.getMessage().startsWith(\"Unexpected operator\"))\n        log.error(\"Parser switch gap in visitFieldOperatorValueCriteria: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Use only is/is not (and is before/is after for dates/states) with multi-value criteria","Keep the grammar switch in visitFieldOperatorValueCriteria in sync with IssueQuery.g4 operators","Log the getRuleName(operator) output when reproducing to identify the offending operator"],"tags":["onedev","issue-query","query-parsing","internal"],"backgroundTag":"unsupported-enum-value","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}