json-path/JsonPath · error · InvalidPathException
Expected path node
Error message
Expected path node
What it means
ValueNode.asPathNode() is the default implementation that every non-path ValueNode inherits; only a real PathNode can be converted. When filter code (e.g. pathNode() or the right() operand handling) calls asPathNode() on a node that is actually a literal (string/number/boolean/json) node, the library throws InvalidPathException("Expected path node").
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java:32
public abstract class ValueNode {
public abstract Class<?> type(Predicate.PredicateContext ctx);
public boolean isPatternNode() {
return false;
}
public PatternNode asPatternNode() {
throw new InvalidPathException("Expected regexp node");
}
public boolean isPathNode() {
return false;
}
public PathNode asPathNode() {
throw new InvalidPathException("Expected path node");
}
public boolean isNumberNode() {
return false;
}
public NumberNode asNumberNode() {
throw new InvalidPathException("Expected number node");
}
public boolean isStringNode() {
return false;
}
public StringNode asStringNode() {
throw new InvalidPathException("Expected string node");
}
View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Call isPathNode() to check the node kind before invoking asPathNode(), and handle literal nodes explicitly.
- Ensure the operand is an unquoted path expression (e.g. @.price) so the parser produces a PathNode, not a string literal.
- When constructing filter nodes programmatically, wrap path expressions in ValueNode.PathNode rather than passing raw literals.
- Add a debug log of the node's class (e.g. node.getClass()) at the call site to see which literal type leaked in.
Example fix
// before
ValueNode node = new ValueNode.StringNode("@.price");
node.asPathNode(); // throws
// after
ValueNode node = new ValueNode.PathNode(Path.compile("@.price"));
if (node.isPathNode()) {
node.asPathNode();
} Defensive patterns
Strategy: type-guard
Validate before calling
// Java: ensure path operands are unquoted path expressions starting with @ or $
void validatePathOperand(String expr) {
if (!(expr.startsWith("@.") || expr.startsWith("$"))) {
throw new IllegalArgumentException("Expected a path operand like @.field, got: " + expr);
}
} Type guard
boolean asPathSafe(ValueNode node) {
return node.isPathNode(); // only then call node.asPathNode()
} Try / catch
try {
return node.asPathNode();
} catch (InvalidPathException e) {
if (e.getMessage().equals("Expected path node")) {
throw new IllegalStateException("Expected a PathNode, got " + node.getClass().getSimpleName(), e);
}
throw e;
} Prevention
- Check isPathNode() before asPathNode().
- Do not quote path operands in filters; quoting turns them into StringNodes.
- Use ValueNode.PathNode (or Path.compile) when constructing nodes programmatically.
- Log node.getClass().getSimpleName() at failing call sites to spot literal leakage.
When it happens
Trigger: A filter predicate where one side must resolve to a JSON path (e.g. comparisons of path-to-path or @.a == @.b style nodes) but the operand parsed as a literal value; calling asPathNode() on a ValueNode obtained from parsing a quoted string or number.
Common situations: Dynamically built filter nodes where a raw string was used where a PathNode was required; expressions referencing document fields that got quoted accidentally, turning them into string nodes; custom filter evaluation code assuming both operands are path nodes.
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
- Expected regexp node
- Expected number node
- Failed to evaluate exists expression
- Could not find matching close quote for %s when parsing : %s
- Could not find matching close for %s when parsing regex in :
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/0239cfca08a7a4a7.
Report an issue: GitHub.