2025, Oct 02 13:00
Fix JSONPath predicate errors in Python: jsonpath-ng vs python-jsonpath for $..[?(@.name=='is_literate')]
Learn why JSONPath $..[?(@.name=='is_literate')] fails in jsonpath-ng, how to handle predicates reliably, and how python-jsonpath returns the expected object.
Filtering JSON by a field with JSONPath sometimes looks deceptively simple, until different implementations disagree on syntax. If you are trying to select an object by name and extract its label, the expression might work in one tool but fail in your Python code. Here is a concise breakdown of why a filter like $..[?(@.name=='is_literate')] may break with jsonpath-ng and how to get consistent results.
Repro: a filter that parses online but fails locally
The goal is to find the object whose name equals is_literate and then read its label. The expression used is $..[?(@.name=='is_literate')]. It evaluates correctly in an online JSONPath tester, but raises a parser error with jsonpath-ng.
from jsonpath_ng.ext import parse
expr_text = "$..[?(@.name=='is_literate')]"
compiled_query = parse(expr_text)
extracted = [hit.value for hit in compiled_query.find(source_payload)]
print(extracted)
The error points at the question mark token, indicating that this syntax is not accepted by the parser.
What’s going on with the predicate
The crux is the filter predicate syntax [?()]. With jsonpath-ng, this form is not accepted in the context shown above, and the parser fails on the ? token. Observations around this behavior include that placing a filter immediately after the recursive descent operator can be problematic, while examples in the package docs follow a pattern like $.objects[?(@some_field > 5)] where a named segment precedes the filter. Attempts such as $..*[?(@name=='is_literate')] avoid the parse error yet still do not return the expected results. In some tests, expressions like $[?(@.name=='is_literate')] or even $[?name=='is_literate'] can yield results, but the original form with $.. and [?()] does not. The parser in jsonpath-ng simply does not support the ? syntax in this usage.
Solution: use a library that supports this filter form
Switching from jsonpath-ng to python-jsonpath resolves the issue. With python-jsonpath, the same predicate expression runs as intended and returns the target object, so you can then read the label using the known name.
import jsonpath
matched_nodes = jsonpath.findall(
    "$..[?(@.name=='is_literate')]",
    source_payload
)
This produces the expected array with the object whose name is is_literate, allowing you to access its label value downstream.
Why this matters
JSONPath looks standardized at a glance, but libraries differ in what they parse and how they evaluate filters. In this case, the predicate syntax with ? works in one tool and fails in another. When your use case depends on filtering by a field to retrieve a sibling like label from a known name, these subtle differences are the difference between a one-liner and a parser error.
Takeaways
If you need to filter by name and fetch a label, and your expression looks like $..[?(@.name=='is_literate')], expect jsonpath-ng to break on the predicate. Either adapt the query to forms that parse for your data shape or switch to python-jsonpath, which accepts the predicate filter in this context and returns the desired object. Being aware of the library’s supported syntax up front prevents time lost on expressions that “work online” but not in your production code.
The article is based on a question from StackOverflow by Lalit mahato and an answer by Lalit mahato.