json-path/JsonPath · error · InvalidPathException
Expected boolean literal
Error message
Expected boolean literal
What it means
Thrown by FilterCompiler.readLogicalOperator when, after parsing the left side of a predicate, the filter ends before a two-character boolean operator can be read. The compiler checks inBounds(end) for the two-char token ('&&' or '||'); if the expression stops right after the left operand (or only one char of the operator remains), it reports 'Expected boolean literal'. It signals a truncated or missing logical connective between two comparisons.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:213
return new RelationalExpressionNode(left, operator, right);
}
catch (InvalidPathException exc) {
filter.setPosition(savepoint);
}
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);
}View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Join multiple comparisons with '&&' or '||' (two characters), never single '&' or '|': "$[?(@.a == 1 && @.b == 2)]"
- Check that the expression is not truncated — ensure there is a complete operator plus right operand after each comparison
- Wrap each comparison in parentheses to make operator grouping explicit: "$[?((@.a == 1) && (@.b == 2))]"
- Print the compiled predicate string before calling read() to spot missing/duplicated characters
Example fix
// before String path = "$[?(@.price < 10 & @.inStock == true)]"; // after String path = "$[?(@.price < 10 && @.inStock == true)]";
Defensive patterns
Strategy: validation
Validate before calling
// Ensure no truncated/trailing single & or | remains
boolean hasCompleteLogicalOps(String predicate) {
return !predicate.matches(".*[^&|][&|][^&|].*") && !predicate.matches(".*[&|]\\s*$");
}
// "@.a == 1 && @.b == 2" -> true; "@.a == 1 &" -> false Type guard
static boolean usesOnlyCompleteOperators(String filter) {
return !java.util.regex.Pattern.compile("(^|[^&|])([&|])($|[^&|])").matcher(filter).find();
} Try / catch
try {
List<Map<String, Object>> hits = JsonPath.parse(json).read(path);
} catch (InvalidPathException e) {
if (e.getMessage().contains("Expected boolean literal")) {
throw new IllegalArgumentException("Use && or || (two chars) between comparisons in: " + path);
}
throw e;
} Prevention
- Always use && / || (doubled) — never single & or |
- Join dynamically built conditions with '&&' constants, not interpolated separators
- Keep a regression test that compiles each production filter expression
- Parenthesize each comparison for readability and safer parsing
When it happens
Trigger: A filter where a second comparison follows without a complete operator: "$[?(@.a == 1 & @.b == 2)]" (single '&'), or "$[?(@.a == 1|)]"; also expressions ending abruptly after the left operand during JsonPath.parse(...).read(path).
Common situations: Using single '&' or '|' instead of '&&'/'||' (SQL or shell habits); copying an expression and losing one character; dynamic path builders that join conditions with the wrong separator; expression truncated by template interpolation.
Related errors
- Expected logical operator
- Unexpected character: %c
- Expected <null> value
- String not closed. Expected
- Expected wildcard token to end with ']' on position
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/15390b626c20e672.
Report an issue: GitHub.