json-path/JsonPath · error · InvalidPathException

Expected string node

Error message

Expected string node

What it means

In JsonPath, ValueNode is a sealed-style base type whose default asStringNode() implementation throws InvalidPathException("Expected string node"). It is thrown when filter evaluation (evaluate/getInput) calls asStringNode() on a node that is not actually a StringNode — e.g. a NumberNode, BooleanNode, or JsonNode produced by evaluating a path on the wrong document shape. It signals a type mismatch between what the filter operator expected (a string operand) and what the JSON document actually contained.

Solutions

  1. Change the filter to match the actual JSON type, e.g. compare numbers without quotes: $.items[?(@.price == 0)] instead of == '0'
  2. Check for null/non-string values in the document and normalize them before filtering, or guard with a nested predicate like $.items[?(@.name && @.name == 'x')]
  3. Cast the value in the document (coerce numbers to strings at serialization time) so operands are consistent
  4. Catch InvalidPathException around the evaluation and treat the mismatching item as a non-match

Example fix

// before
List<Map<String,Object>> hits = JsonPath.parse(json).read("$.items[?(@.code == '123')]"); // code is a number
// after
List<Map<String,Object>> hits = JsonPath.parse(json).read("$.items[?(@.code == 123)]");
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = JsonPath.parse(json).read("$.item.price");
if (v == null || !(v instanceof String)) throw new IllegalArgumentException("price must be a string for this filter");

Type guard

static boolean isStringOperand(Object o) { return o instanceof String; }

Try / catch

try {
    return JsonPath.parse(json).read("$.items[?(@.code == '123')]");
} catch (InvalidPathException e) {
    // operand type mismatch: treat as non-match or re-run with corrected literal
    return Collections.emptyList();
}

Prevention

When it happens

Trigger: Using string comparison operators (==, =~, in, like, etc.) in a JSONPath filter where the evaluated operand is not a string, e.g. $.items[?(@.price == 'free')] where price is a number, or a path operand resolving to null/boolean instead of a string. Also calling StringNode.asStringNode() via evaluate/getInput on a subclass node.

Common situations: Filter predicates written against documents where field types vary (one record has "name": "x", another has name: null); comparing numeric fields to quoted string literals; migrating documents from loosely typed sources where an expected string field arrives as a number or object.

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


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

Appendix: source

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

    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");
    }

    public boolean isBooleanNode() {
        return false;
    }

    public BooleanNode asBooleanNode() {
        throw new InvalidPathException("Expected boolean node");
    }

    public boolean isJsonNode() {
        return false;
    }

    public JsonNode asJsonNode() {
        throw new InvalidPathException("Expected json node");
    }

View on GitHub (pinned to 62a4c9f0f6)