{"record":{"id":"9f609f5a7763d709","repo":"json-path/JsonPath","slug":"expected-logical-operator","errorCode":null,"errorMessage":"Expected logical operator","messagePattern":"Expected logical operator","errorType":"exception","errorClass":"InvalidPathException","httpStatus":null,"severity":"error","filePath":"json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java","lineNumber":217,"sourceCode":"        }\n\n        PathNode pathNode = left.asPathNode();\n        left = pathNode.asExistsCheck(pathNode.shouldExists());\n        RelationalOperator operator = RelationalOperator.EXISTS;\n        ValueNode right = left.asPathNode().shouldExists() ? ValueNodes.TRUE : ValueNodes.FALSE;\n        return new RelationalExpressionNode(left, operator, right);\n    }\n\n    private LogicalOperator readLogicalOperator(){\n        int begin = filter.skipBlanks().position();\n        int end = begin+1;\n\n        if(!filter.inBounds(end)){\n            throw new InvalidPathException(\"Expected boolean literal\");\n        }\n        CharSequence logicalOperator = filter.subSequence(begin, end+1);\n        if(!logicalOperator.equals(\"||\") && !logicalOperator.equals(\"&&\")){\n            throw new InvalidPathException(\"Expected logical operator\");\n        }\n        filter.incrementPosition(logicalOperator.length());\n        logger.trace(\"LogicalOperator from {} to {} -> [{}]\", begin, end, logicalOperator);\n\n        return LogicalOperator.fromString(logicalOperator.toString());\n    }\n\n    private RelationalOperator readRelationalOperator() {\n        int begin = filter.skipBlanks().position();\n\n        if(isRelationalOperatorChar(filter.currentChar())){\n            while (filter.inBounds() && isRelationalOperatorChar(filter.currentChar())) {\n                filter.incrementPosition(1);\n            }\n        } else {\n            while (filter.inBounds() && filter.currentChar() != SPACE) {\n                filter.incrementPosition(1);\n            }","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/json-path/JsonPath/blob/62a4c9f0f65ba3f625aa0867d64c528ba72d09ec/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java#L199-L235","documentation":"Thrown by FilterCompiler.readLogicalOperator when the two-character sequence at the current position is neither '||' nor '&&'. The compiler reads a two-char token and, if it is not a recognized logical operator, raises 'Expected logical operator'. It means an unexpected token (or an unsupported operator spelling) sits where a boolean connective is required between predicate operands.","triggerScenarios":"A filter containing an operator other than &&/|| between comparisons, e.g. \"and\"/\"or\" as words (\"$[?(@.a == 1 and @.b == 2)]\"), 'AND', or a stray single character; hit via Filter.compile or path read with an inline filter predicate.","commonSituations":"Translating expressions from other query languages (SQL 'AND'/'OR') into JsonPath; accidentally embedding comparison operators like '==' where a connective belongs; typos such as '& &' or '| |'.","solutions":["Replace word operators with the symbolic form: use '&&' for AND and '||' for OR — JsonPath filters do not accept 'and'/'or'","Combine comparisons into a single condition when possible: \"$[?(@.a > 1 && @.a < 10)]\"","Escape or move stray characters out of the predicate — verify every token between comparisons is exactly '&&' or '||'","Test the predicate with Filter.compile() to isolate the failing position"],"exampleFix":"// before\nString path = \"$[?(@.a == 1 or @.b == 2)]\";\n// after\nString path = \"$[?(@.a == 1 || @.b == 2)]\";","handlingStrategy":"validation","validationCode":"// Reject word operators before compiling\nboolean validOperators(String predicate) {\n    return !predicate.toLowerCase().matches(\".*\\\\b(and|or)\\\\b.*\");\n}\n// validOperators(\"$[?(@.a == 1 and @.b == 2)]\") -> false","typeGuard":"static boolean containsWordOperator(String filter) {\n    return java.util.regex.Pattern.compile(\"\\\\b(and|or|AND|OR)\\\\b\").matcher(filter).find();\n}","tryCatchPattern":"try {\n    Filter f = Filter.compile(predicate);\n} catch (InvalidPathException e) {\n    if (e.getMessage().contains(\"Expected logical operator\")) {\n        String fixed = predicate.replaceAll(\"(?i)\\\\band\\\\b\", \"&&\").replaceAll(\"(?i)\\\\bor\\\\b\", \"||\");\n        return Filter.compile(fixed);\n    }\n    throw e;\n}","preventionTips":["JsonPath only accepts symbolic && and || — never 'and'/'or'/'AND'/'OR'","When migrating expressions from SQL/SpEL, mechanically replace word operators first","Lint filter strings with a regex for forbidden word operators at input boundaries","Prefer the Filter.Builder API (filter(where(...).and(...))) which avoids raw operator strings entirely"],"tags":["json-path","filter-compiler","logical-operator","path-syntax"],"backgroundTag":"invalid-path-expression","analyzedSha":"62a4c9f0f65ba3f625aa0867d64c528ba72d09ec","analyzedAt":"2026-09-11T11:36:00.448Z","contentChangedAt":"2026-09-11T11:36:00.448Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}