json-path/JsonPath · error · PathNotFoundException

Expected to find an object with property %s in path %s but f

Error message

Expected to find an object with property %s in path %s but found '%s'. This is not a json object according to the JsonProvider: '%s'.

What it means

During evaluation, PropertyPathToken needs to read a property from a JSON object (Map). If the current model node is not a Map (e.g. an array, string, number, or null), the property cannot be looked up. The library throws PathNotFoundException instead of a hard type error because the path simply does not resolve, unless SUPPRESS_EXCEPTIONS is set or the upstream path is indefinite (in which case it silently returns).

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/path/PropertyPathToken.java:72

    }

    public boolean multiPropertyIterationCase() {
        // Semantics of this case is the same as semantics of ArrayPathToken with INDEX_SEQUENCE operation.
        return !isLeaf() && properties.size() > 1;
    }

    @Override
    public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
        // Can't assert it in ctor because isLeaf() could be changed later on.
        assert onlyOneIsTrueNonThrow(singlePropertyCase(), multiPropertyMergeCase(), multiPropertyIterationCase());

        if (!ctx.jsonProvider().isMap(model)) {
            if (!isUpstreamDefinite()
                    || ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)) {
                return;
            } else {
                String m = model == null ? "null" : model.getClass().getName();
                throw new PathNotFoundException(String.format(
                        "Expected to find an object with property %s in path %s but found '%s'. " +
                                "This is not a json object according to the JsonProvider: '%s'.",
                        getPathFragment(), currentPath, m, ctx.configuration().jsonProvider().getClass().getName()));
            }
        }

        if (singlePropertyCase() || multiPropertyMergeCase()) {
            handleObjectProperty(currentPath, model, ctx, properties);
            return;
        }

        assert multiPropertyIterationCase();
        final List<String> currentlyHandledProperty = new ArrayList<String>(1);
        currentlyHandledProperty.add(null);
        for (final String property : properties) {
            currentlyHandledProperty.set(0, property);
            handleObjectProperty(currentPath, model, ctx, currentlyHandledProperty);
        }

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Fix the path so it matches the actual document shape (add array iteration [*] or filters where the node is an array)
  2. Validate/inspect the document before reading (e.g. read the parent node and check it is a Map)
  3. Add Option.SUPPRESS_EXCEPTIONS to the Configuration if a miss is acceptable and null/absence should be tolerated
  4. Use definitive(...) or JsonPath.parse(...).read with default value handling (read(path, default)) for optional fields

Example fix

// before
String name = JsonPath.read(json, "$.user.name"); // throws if user is a string/null
// after
Object user = JsonPath.read(json, "$.user");
String name = (user instanceof Map) ? JsonPath.read(json, "$.user.name") : null;
Defensive patterns

Strategy: type-guard

Validate before calling

Object parent = JsonPath.read(json, "$.user");
if (!(parent instanceof Map)) throw new IllegalStateException("$.user is not an object");

Type guard

boolean isObject(Object o) { return o instanceof Map<?, ?>; }

Try / catch

try {
    return JsonPath.read(json, "$.user.name");
} catch (PathNotFoundException e) {
    return null; // or default value
}

Prevention

When it happens

Trigger: Evaluating $.foo.bar where $.foo resolves to a string/number/array/null instead of an object; calling JsonPath.read on a document whose structure differs from the expected schema; using definite paths against documents where an intermediate node is a primitive.

Common situations: API responses that changed shape (field is now a scalar or missing); reading paths like $.user.name when user is null; querying arrays with object-property paths without the correct [?] filter or ['..'] wildcard; mismatched schema between producer and consumer services.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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