FasterXML/jackson-databind · error · IllegalArgumentException

Cannot deserialize Proxy class {} as a Bean

Error message

Cannot deserialize Proxy class {} as a Bean

What it means

Thrown by BeanDeserializerFactory.isPotentialBeanType when the target class is a JDK dynamic proxy (java.lang.reflect.Proxy subclass). Proxies have no real fields or constructors Jackson can introspect, so bean deserialization is impossible and rejected up front.

Source

Thrown at src/main/java/tools/jackson/databind/deser/BeanDeserializerFactory.java:1071

    /**********************************************************
     */

    /**
     * Helper method used to skip processing for types that we know
     * cannot be (i.e. are never consider to be) beans:
     * things like primitives, Arrays, Enums, and proxy types.
     *<p>
     * Note that usually we shouldn't really be getting these sort of
     * types anyway; but better safe than sorry.
     */
    protected boolean isPotentialBeanType(Class<?> type)
    {
        String typeStr = ClassUtil.canBeABeanType(type);
        if (typeStr != null) {
            throw new IllegalArgumentException("Cannot deserialize Class "+type.getName()+" (of type "+typeStr+") as a Bean");
        }
        if (ClassUtil.isProxyType(type)) {
            throw new IllegalArgumentException("Cannot deserialize Proxy class "+type.getName()+" as a Bean");
        }
        // [databind#3229]: Local/anonymous classes cannot be instantiated but
        //   can still be updated via `readerForUpdating()`. So let them through
        //   here; if actual instantiation is attempted, `ValueInstantiator` will
        //   fail with a clear error.
        return true;
    }

    /**
     * Helper method that will check whether given raw type is marked as always ignorable
     * (for purpose of ignoring properties with type)
     */
    protected boolean isIgnorableType(DeserializationContext ctxt, BeanPropertyDefinition propDef,
            Class<?> type, Map<Class<?>,Boolean> ignoredTypes)
    {
        Boolean status = ignoredTypes.get(type);
        if (status != null) {
            return status.booleanValue();

View on GitHub (pinned to a50c7d2a1d)

Solutions

  1. Deserialize into the concrete entity class, not the proxy class.
  2. For Hibernate, ensure entities are initialized/deproxied first (Hibernate.unproxy / HibernateProxyHelper.getClassWithoutInitializingProxy).
  3. Use a mixin or @JsonTypeInfo to map the proxy class to its concrete base.
  4. Keep persistence/AOP concerns out of the Jackson boundary; convert to plain DTOs first.

Example fix

// before
Object entity = mapper.readValue(json, hibernateProxy.getClass()); // Proxy class -> throws
// after
Class<?> concrete = Hibernate.unproxy(hibernateProxy).getClass();
Object entity = mapper.readValue(json, concrete);
Defensive patterns

Strategy: validation

Validate before calling

Class<?> target = value.getClass();
if (java.lang.reflect.Proxy.isProxyClass(target)) {
    throw new IllegalArgumentException("Cannot deserialize into proxy class " + target);
}
mapper.readValue(json, target);

Prevention

When it happens

Trigger: Deserializing into a class that is or extends java.lang.reflect.Proxy — most often a Hibernate lazy-loading proxy class, a Spring AOP proxy class, or a manually-proxied interface that leaked into the target type.

Common situations: Passing a Hibernate uninitialized entity proxy class as the deserialization target; round-tripping a serialized proxy back into the proxy class; AOP-wrapped domain objects reaching the mapper.

Related errors


AI-assisted analysis of FasterXML/jackson-databind@a50c7d2a1d (2026-08-06). Data as JSON: /api/errors/a6080b7fda6b3f97. Report an issue: GitHub.