apache/dubbo · error · ClassCastException

value ' ' for key ' ' in ' ' is not List

Error message

value '%s' for key '%s' in '%s' is not List

What it means

Thrown by AbstractJsonUtilImpl.getList(Map,String) when obj contains key but its value is not a java.util.List. getList returns null for an absent key, so this exception only fires when the key IS present but the JSON value is a scalar, object, or other non-list type. It is a ClassCastException reflecting a schema/type mismatch between the JSON shape and the expected Java type. Subclasses (the JsonUtil impls) inherit this behavior.

Solutions

  1. Confirm the actual runtime type of obj.get(key) and reconcile with the schema — typically the field shape changed upstream.
  2. If the field may legitimately be a scalar or a list, branch on instanceof List before calling getList.
  3. Switch to a more permissive accessor or normalize the JSON to the expected array shape upstream.
  4. Catch ClassCastException and report the offending key/value for triage.

Example fix

// before
List<?> items = jsonUtil.getList(obj, "items");
// after - tolerate single-or-list
Object raw = obj.get("items");
List<?> items = raw instanceof List ? (List<?>) raw : (raw == null ? null : List.of(raw));
Defensive patterns

Strategy: type-guard

Validate before calling

Object raw = obj.get(key);
if (raw != null && !(raw instanceof List)) {
    // field present but not a list; decide policy before calling getList
    return Collections.emptyList();
}
return jsonUtil.getList(obj, key);

Type guard

private static boolean isListOfMapsOrEmpty(Object value) {
    return value == null || value instanceof List;
}

Try / catch

try {
    return jsonUtil.getList(obj, key);
} catch (ClassCastException e) {
    log.warn("expected list at key={}, got value={}", key, obj.get(key));
    return null; // or a domain-specific fallback
}

Prevention

When it happens

Trigger: jsonUtil.getList(obj, key) where obj.get(key) exists and is a Map, String, Number, Boolean, or null-reference that is not a List instance. For example JSON {"items": {"a":1}} with getList(obj, "items").

Common situations: API contract changed so a field that was an array became a single object (or vice versa); a conditional payload where the field is sometimes a list and sometimes a scalar; downstream service returning an error object instead of the expected array; using getList on a field the schema documents as an object.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/7d76bf6f40a16428. Report an issue: GitHub.

Appendix: source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java:55

            List<String> list = new LinkedList<>();
            list.add("json");
            return CollectionUtils.equals(list, toJavaList(toJson(list), String.class));
        } catch (Throwable t) {
            return false;
        }
    }

    @Override
    public List<?> getList(Map<String, ?> obj, String key) {
        assert obj != null;
        assert key != null;
        if (!obj.containsKey(key)) {
            return null;
        }
        Object value = obj.get(key);
        if (!(value instanceof List)) {
            throw new ClassCastException(String.format("value '%s' for key '%s' in '%s' is not List", value, key, obj));
        }
        return (List<?>) value;
    }

    /**
     * Gets a list from an object for the given key, and verifies all entries are objects.  If the key
     * is not present, this returns null.  If the value is not a List or an entry is not an object,
     * throws an exception.
     */
    @Override
    public List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {
        assert obj != null;
        List<?> list = getList(obj, key);
        if (list == null) {
            return null;
        }
        return checkObjectList(list);
    }

View on GitHub (pinned to 3a3043227f)