apache/dubbo · error · IllegalArgumentException

`name` filed should be string!

Error message

`name` filed should be string!

What it means

When PojoUtils.realize encounters a Map representing an enum type, it extracts the 'name' key to reconstruct the enum constant via Enum.valueOf. If the value associated with 'name' is non-null but not a String (e.g. an Integer or another Map), Enum.valueOf cannot be called and an IllegalArgumentException is thrown.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java:472

        if (pojo instanceof Map<?, ?> && type != null) {
            Object className = ((Map<Object, Object>) pojo).get("class");
            if (className instanceof String) {
                if (!CLASS_NOT_FOUND_CACHE.containsKey(className)) {
                    try {
                        type = DefaultSerializeClassChecker.getInstance()
                                .loadClass(ClassUtils.getClassLoader(), (String) className);
                    } catch (ClassNotFoundException e) {
                        CLASS_NOT_FOUND_CACHE.put((String) className, NOT_FOUND_VALUE);
                    }
                }
            }

            // special logic for enum
            if (type.isEnum()) {
                Object name = ((Map<Object, Object>) pojo).get("name");
                if (name != null) {
                    if (!(name instanceof String)) {
                        throw new IllegalArgumentException("`name` filed should be string!");
                    } else {
                        return Enum.valueOf((Class<Enum>) type, (String) name);
                    }
                }
            }
            Map<Object, Object> map;
            // when return type is not the subclass of return type from the signature and not an interface
            if (!type.isInterface() && !type.isAssignableFrom(pojo.getClass())) {
                try {
                    map = (Map<Object, Object>) type.getDeclaredConstructor().newInstance();
                    Map<Object, Object> mapPojo = (Map<Object, Object>) pojo;
                    map.putAll(mapPojo);
                    if (GENERIC_WITH_CLZ) {
                        map.remove("class");
                    }
                } catch (Exception e) {
                    // ignore error
                    map = (Map<Object, Object>) pojo;

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Ensure the generic representation of an enum always uses a String value for the 'name' key matching an actual enum constant name.
  2. If the source sends ordinals, convert them to the enum constant name before passing to realize.
  3. On the consumer side, verify the serialization framework encodes enums as their name string, not ordinal.
  4. For custom Map construction, explicitly cast: map.put("name", enumValue.name()).

Example fix

// before
Map<String, Object> map = new HashMap<>();
map.put("name", 1); // ordinal — throws
MyEnum result = (MyEnum) PojoUtils.realize(map, MyEnum.class);
// after
map.put("name", MyEnum.ACTIVE.name()); // String constant name
Defensive patterns

Strategy: validation

Validate before calling

// Validate enum 'name' field is a String before calling realize
if (type.isEnum() && pojo instanceof Map) {
    Object nameVal = ((Map<?, ?>) pojo).get("name");
    if (nameVal != null && !(nameVal instanceof String)) {
        throw new IllegalArgumentException(
            "Enum 'name' must be String, got " + nameVal.getClass());
    }
}
PojoUtils.realize(pojo, type);

Type guard

// Type guard for enum map representations
static boolean isValidEnumMap(Object pojo, Class<?> type) {
    if (!type.isEnum() || !(pojo instanceof Map)) return true;
    Object name = ((Map<?, ?>) pojo).get("name");
    return name == null || name instanceof String;
}

Prevention

When it happens

Trigger: Calling PojoUtils.realize on a Map that targets an enum class, where the 'name' entry is a non-String type. This happens during generic RPC deserialization when the wire format (e.g. a custom JSON parser or a non-Java client) sends the enum name as a numeric ordinal or a structured object instead of a plain string.

Common situations: A non-Java consumer (Python, Go, Node.js) calling a Dubbo service via generic invocation that sends an enum as {"name": 1} (ordinal) instead of {"name": "ACTIVE"}. Also a misconfigured serializer or a manual Map construction where the 'name' key was set to the wrong type.

Related errors


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