json-path/JsonPath · error · UnsupportedOperationException

an array or object instance is expected

Error message

an array or object instance is expected

What it means

JakartaJsonProvider.toIterable() converts a JSON value into an Iterable of unwrapped Java objects. It only supports JsonArray (or JsonArrayBuilder) and JsonObject (or JsonObjectBuilder) inputs; anything else — a scalar string, number, boolean, or null — triggers UnsupportedOperationException('an array or object instance is expected'). The library throws it because iteration is only defined over the two JSON container types.

Solutions

  1. Check the actual type of the path result first (obj instanceof JsonArray || obj instanceof JsonObject, or use provider.isArray/isMap) before iterating
  2. Adjust the JsonPath to select a container, e.g. use '$.field[*]' or '$.field.arrayProperty' instead of a scalar property
  3. Catch UnsupportedOperationException and treat the value as a scalar: wrap it in a single-element list instead of iterating
  4. If the value is legitimately nullable, guard null before calling paths that force iteration

Example fix

// before
Iterable<Object> vals = JsonPath.parse(json).read("$.items"); // $.items is "foo"
// after
Object res = JsonPath.parse(json).read("$.items");
Iterable<Object> vals = (res instanceof List || res instanceof Map)
    ? JsonPath.parse(json).read("$.items")
    : java.util.Collections.singletonList(res);
Defensive patterns

Strategy: type-guard

Validate before calling

// Java
private static boolean isIterableContainer(Object obj) {
    return obj instanceof List || obj instanceof Map || obj instanceof JsonArray || obj instanceof JsonObject;
}

Type guard

if (obj instanceof JsonArray || obj instanceof JsonArrayBuilder || obj instanceof JsonObject || obj instanceof JsonObjectBuilder) {
    // safe to iterate via provider.toIterable(obj)
} else {
    // treat as scalar: singletonList(obj)
}

Try / catch

try {
    Iterable<?> it = provider.toIterable(obj);
} catch (UnsupportedOperationException e) {
    Iterable<?> it = Collections.singletonList(obj);
}

Prevention

When it happens

Trigger: Evaluating a JsonPath (e.g. with JsonPath.using(JakartaJsonProvider...).read(path)) whose result is a scalar like '$.name' or '$' pointing at a string/number/boolean/null, then iterating the result; calling toIterable(obj) directly with a non-container value; applying wildcard/deep-scan paths whose provider internals call toIterable on a leaf node.

Common situations: Paths written expecting an array but the document actually holds a scalar (API changed shape); reading '$.field' instead of '$.field[*]'; a null JSON value being iterated; using the Jakarta EE JSON-P provider against documents where the target of the path is a primitive.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        List<Object> values;
        if (isArray(obj)) {
            if (obj instanceof JsonArrayBuilder) {
                obj = ((JsonArrayBuilder) obj).build();
            }
            values = new ArrayList<Object>(((List<?>) obj).size());
            for (Object val : ((List<?>) obj)) {
                values.add(unwrap(val));
            }
        } else if (isMap(obj)) {
            if (obj instanceof JsonObjectBuilder) {
                obj = ((JsonObjectBuilder) obj).build();
            }
            values = new ArrayList<Object>(((JsonObject) obj).size());
            for (JsonValue val : ((JsonObject) obj).values()) {
                values.add(unwrap(val));
            }
        } else {
            throw new UnsupportedOperationException("an array or object instance is expected");
        }
        return values;
    }

    @Override
    public Object unwrap(Object obj) {
        if (obj == null) {
            return null;
        }
        if (!(obj instanceof JsonValue)) {
            return obj;
        }
        switch (((JsonValue) obj).getValueType()) {
        case ARRAY:
        	if (mutableJson && obj instanceof JsonArrayProxy) {
        		return (JsonArray) obj;
        	} else {
        		return ((JsonArray) obj).getValuesAs((JsonValue v) -> unwrap(v));

View on GitHub (pinned to 62a4c9f0f6)