json-path/JsonPath · error · UnsupportedOperationException

Json object is expected

Error message

Json object is expected

What it means

getPropertyKeys only supports JsonObjectBuilder and JsonObject; any other node type (JsonArray, JsonString, numbers, null, plain Java objects) triggers UnsupportedOperationException "Json object is expected". The caller asked for the key set of something that is not a JSON object.

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/spi/json/JakartaJsonProvider.java:257

        } else {
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public boolean isMap(Object obj) {
        return (obj instanceof JsonObject || obj instanceof JsonObjectBuilder);
    }

    @Override
    public Collection<String> getPropertyKeys(Object obj) {
        Set<String> keys;
        if (obj instanceof JsonObjectBuilder) {
            keys = ((JsonObjectBuilder) obj).build().keySet();
        } else if (obj instanceof JsonObject) {
            keys = ((JsonObject) obj).keySet();
        } else {
            throw new UnsupportedOperationException("Json object is expected");
        }
        return new ArrayList<String>(keys);
    }

    @Override
    public int length(Object obj) {
        if (isArray(obj)) {
            if (obj instanceof JsonArrayBuilder) {
                return ((JsonArrayBuilder) obj).build().size();
            } else {
                return ((List<?>) obj).size();
            }
        } else if (isMap(obj)) {
            if (obj instanceof JsonObjectBuilder) {
                obj = ((JsonObjectBuilder) obj).build();
            }
            return ((JsonObject) obj).size();
        } else {

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Check the node type (instanceof JsonObject) before requesting property keys.
  2. Fix the path expression to select an object member rather than an array or scalar.
  3. For arrays, iterate elements with toIterable/length and call getPropertyKeys per element.
  4. Handle null/missing paths upstream so getPropertyKeys is never called with null.

Example fix

// before
List<String> keys = provider.getPropertyKeys(node);
// after
if (node instanceof JsonObject) {
    List<String> keys = provider.getPropertyKeys(node);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Java
if (node == null || !(node instanceof JsonObject || node instanceof JsonObjectBuilder)) {
    throw new IllegalStateException("Expected JSON object at path");
}

Type guard

// Java
static boolean isJsonObject(Object o) {
    return o instanceof JsonObject || o instanceof JsonObjectBuilder;
}

Try / catch

try { keys = provider.getPropertyKeys(node); } catch (UnsupportedOperationException e) { keys = Collections.emptyList(); }

Prevention

When it happens

Trigger: Calling getPropertyKeys on a node that resolved to an array, scalar, or null — e.g. a JsonPath expression like $.items (an array) or $.missing (null) instead of $.items[0].someObject.

Common situations: Iterating keys of a query result that turned out to be an array or absent value due to a wrong path expression or schema drift in the data.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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