quarkusio/quarkus · error · RuntimeException

Unable to serialize objects of type ${param.getClass()} to b

Error message

Unable to serialize objects of type ${param.getClass()} to bytecode as it has no default constructor

What it means

The recorder can only rebuild collection-like or bean objects at runtime if it can instantiate them. For a type it does not specially handle (List/Set/Map/known interfaces) and that has no default constructor, there is no way to create the instance during replay, so serialization is refused.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java:1593

                        }
                    } else {
                        try {
                            param.getClass().getDeclaredConstructor();
                            out = method.newInstance(ofConstructor(param.getClass()));
                        } catch (NoSuchMethodException e) {
                            //fallback for collection types, such as unmodifiableMap
                            if (SortedMap.class.isAssignableFrom(expectedType)) {
                                out = method.newInstance(ofConstructor(TreeMap.class));
                            } else if (Map.class.isAssignableFrom(expectedType)) {
                                out = method.newInstance(ofConstructor(LinkedHashMap.class));
                            } else if (List.class.isAssignableFrom(expectedType)) {
                                out = method.newInstance(ofConstructor(ArrayList.class));
                            } else if (SortedSet.class.isAssignableFrom(expectedType)) {
                                out = method.newInstance(ofConstructor(TreeSet.class));
                            } else if (Set.class.isAssignableFrom(expectedType)) {
                                out = method.newInstance(ofConstructor(LinkedHashSet.class));
                            } else {
                                throw new RuntimeException("Unable to serialize objects of type " + param.getClass()
                                        + " to bytecode as it has no default constructor");
                            }
                        }
                    }
                }
                return out;
            }
        };

        //now return the actual deferred parameter that represents the result of construction
        return new DeferredArrayStoreParameter(param, expectedType) {

            @Override
            void doPrepare(MethodContext context) {
                //this is where the object construction happens
                //first create the actual object
                for (SerializationStep i : ctorSetupSteps) {
                    i.prepare(context);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a public no-arg constructor to the class and populate via setters
  2. Use a standard type (ArrayList/HashSet/HashMap or their interfaces) instead of the custom type
  3. Register the class for recording with an explicit recordable constructor (@Inject constructor or registered paramGenerator)
  4. Convert the value to a supported representation before recording

Example fix

// before
new CustomIntList(42) // no default ctor
// after
List<Integer> list = new ArrayList<>(); // default ctor, standard type
Defensive patterns

Strategy: validation

Validate before calling

boolean instantiable(Class<?> c) {
    if (List.class.isAssignableFrom(c) || Set.class.isAssignableFrom(c)
        || Map.class.isAssignableFrom(c)) return true;
    try { c.getConstructor(); return true; } catch (NoSuchMethodException e) { return false; }
}
if (!instantiable(value.getClass())) throw new IllegalStateException("No default ctor: " + value.getClass());

Type guard

boolean hasDefaultConstructor(Class<?> c) {
    try { c.getDeclaredConstructor(); return true; }
    catch (NoSuchMethodException e) { return false; }
}

Try / catch

try {
    recorder.record(value);
} catch (RuntimeException e) {
    if (String.valueOf(e.getMessage()).contains("has no default constructor")) {
        throw new IllegalStateException("Add a no-arg constructor or use a standard type for " + value.getClass(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing an object whose class has no no-arg constructor and is not a List/SortedSet/Set/Map or a registered-recordable type into a @Record method — e.g. a custom immutable collection or a class with only parameterized constructors.

Common situations: Custom collection implementations; value objects with only all-args constructors; third-party types placed on config classes.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/962a7d6244a2406e. Report an issue: GitHub.