json-path/JsonPath · error · InvalidPathException

Expected logical operator

Error message

Expected logical operator

What it means

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.

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:217

        }

        PathNode pathNode = left.asPathNode();
        left = pathNode.asExistsCheck(pathNode.shouldExists());
        RelationalOperator operator = RelationalOperator.EXISTS;
        ValueNode right = left.asPathNode().shouldExists() ? ValueNodes.TRUE : ValueNodes.FALSE;
        return new RelationalExpressionNode(left, operator, right);
    }

    private LogicalOperator readLogicalOperator(){
        int begin = filter.skipBlanks().position();
        int end = begin+1;

        if(!filter.inBounds(end)){
            throw new InvalidPathException("Expected boolean literal");
        }
        CharSequence logicalOperator = filter.subSequence(begin, end+1);
        if(!logicalOperator.equals("||") && !logicalOperator.equals("&&")){
            throw new InvalidPathException("Expected logical operator");
        }
        filter.incrementPosition(logicalOperator.length());
        logger.trace("LogicalOperator from {} to {} -> [{}]", begin, end, logicalOperator);

        return LogicalOperator.fromString(logicalOperator.toString());
    }

    private RelationalOperator readRelationalOperator() {
        int begin = filter.skipBlanks().position();

        if(isRelationalOperatorChar(filter.currentChar())){
            while (filter.inBounds() && isRelationalOperatorChar(filter.currentChar())) {
                filter.incrementPosition(1);
            }
        } else {
            while (filter.inBounds() && filter.currentChar() != SPACE) {
                filter.incrementPosition(1);
            }

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Replace word operators with the symbolic form: use '&&' for AND and '||' for OR — JsonPath filters do not accept 'and'/'or'
  2. Combine comparisons into a single condition when possible: "$[?(@.a > 1 && @.a < 10)]"
  3. Escape or move stray characters out of the predicate — verify every token between comparisons is exactly '&&' or '||'
  4. Test the predicate with Filter.compile() to isolate the failing position

Example fix

// before
String path = "$[?(@.a == 1 or @.b == 2)]";
// after
String path = "$[?(@.a == 1 || @.b == 2)]";
Defensive patterns

Strategy: validation

Validate before calling

// Reject word operators before compiling
boolean validOperators(String predicate) {
    return !predicate.toLowerCase().matches(".*\\b(and|or)\\b.*");
}
// validOperators("$[?(@.a == 1 and @.b == 2)]") -> false

Type guard

static boolean containsWordOperator(String filter) {
    return java.util.regex.Pattern.compile("\\b(and|or|AND|OR)\\b").matcher(filter).find();
}

Try / catch

try {
    Filter f = Filter.compile(predicate);
} catch (InvalidPathException e) {
    if (e.getMessage().contains("Expected logical operator")) {
        String fixed = predicate.replaceAll("(?i)\\band\\b", "&&").replaceAll("(?i)\\bor\\b", "||");
        return Filter.compile(fixed);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Translating expressions from other query languages (SQL 'AND'/'OR') into JsonPath; accidentally embedding comparison operators like '==' where a connective belongs; typos such as '& &' or '| |'.

Related errors


AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11). Data as JSON: /api/errors/9f609f5a7763d709. Report an issue: GitHub.