json-path/JsonPath · error · JsonPathException
Failed to evaluate exists expression
Error message
Failed to evaluate exists expression
What it means
The ExistsEvaluator handles the 'exists' filter operator. It requires that at least one side of the comparison is a boolean ValueNode; when neither the left nor the right operand is a boolean node it cannot perform the exists comparison and throws JsonPathException with this message. In practice it means the filter expression's operand types don't fit the exists operator.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java:50
evaluators.put(RelationalOperator.NIN, new NotInEvaluator());
evaluators.put(RelationalOperator.ALL, new AllEvaluator());
evaluators.put(RelationalOperator.CONTAINS, new ContainsEvaluator());
evaluators.put(RelationalOperator.MATCHES, new PredicateMatchEvaluator());
evaluators.put(RelationalOperator.TYPE, new TypeEvaluator());
evaluators.put(RelationalOperator.SUBSETOF, new SubsetOfEvaluator());
evaluators.put(RelationalOperator.ANYOF, new AnyOfEvaluator());
evaluators.put(RelationalOperator.NONEOF, new NoneOfEvaluator());
}
public static Evaluator createEvaluator(RelationalOperator operator){
return evaluators.get(operator);
}
private static class ExistsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(!left.isBooleanNode() && !right.isBooleanNode()){
throw new JsonPathException("Failed to evaluate exists expression");
}
return left.asBooleanNode().getBoolean() == right.asBooleanNode().getBoolean();
}
}
private static class NotEqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return !evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx);
}
}
private static class TypeSafeNotEqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return !evaluators.get(RelationalOperator.TSEQ).evaluate(left, right, ctx);
}
}View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Rewrite the filter so exists checks a path against a boolean, e.g. ?(@.isbn exists true) or simply use ?(@.isbn) / ?(@.isbn != null) for presence checks.
- Use Criteria API: Criteria.where("isbn").exists(true) (or ne(null)) instead of hand-built operand nodes.
- Verify the ValueNode types you pass if using the internal filter/Evaluator API directly; wrap operands with ValueNode.createBooleanNode.
Example fix
// before
Filter f = filter(where("price").exists("yes")); // neither side boolean -> JsonPathException
// after
Filter f = filter(where("price").exists(true));
// or for presence checks:
Filter f2 = filter(where("price").ne(null)); Defensive patterns
Strategy: type-guard
Validate before calling
// ensure exists operands are boolean
if (!(leftNode instanceof BooleanNode) && !(rightNode instanceof BooleanNode)) {
throw new IllegalArgumentException("exists operator requires a boolean operand");
} Type guard
static boolean isBooleanNode(ValueNode n) {
return n != null && n.isBooleanNode();
} Try / catch
try {
return filter(where(field).exists(true)).eval(ctx);
} catch (JsonPathException e) {
if ("Failed to evaluate exists expression".equals(e.getMessage())) {
return filter(where(field).ne(null)).eval(ctx);
}
throw e;
} Prevention
- Always pair the exists operator with a boolean literal (true/false).
- Prefer the Criteria API (.exists(true), .ne(null)) over hand-built filter strings.
- Check JsonPath version notes: exists semantics differ across releases.
When it happens
Trigger: Using a filter predicate like $.book[?(@.isbn exists true)] (or similar exists/not-exists style expressions in Filter API) where the operands were parsed as non-boolean ValueNodes — e.g. writing 'exists' comparisons against string/number literals, or composing ValueNode-based criteria where neither side is a PathNode evaluated to boolean.
Common situations: Hand-writing filter strings with the exists operator against fields whose values are strings or numbers; migrating filter syntax between JsonPath versions where exists semantics changed; building Criteria programmatically and passing non-boolean operands to an exists-style evaluation.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Can only rename properties in a map
- Can only add to an array
- Can only add properties to a map
- Expected regexp node
- Expected path node
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/19b124b80836d0e8.
Report an issue: GitHub.