quarkusio/quarkus · error · RuntimeException

Unable to serialize ${param} as the wrong number of paramete

Error message

Unable to serialize ${param} as the wrong number of parameters were generated for ${nonDefaultConstructorHolder.constructor}

What it means

Bytecode recording of a non-default-constructor object requires a registered paramGenerator that produces exactly the constructor's arguments at record time. When the generator returns a list whose size differs from the constructor's parameter count, serialization is aborted. This is a bug in the extension that registered the constructor (via io.quarkus.deployment.recording.RecordableConstructor or ConstructorParameterCustomizer-style registration), not typically a user config mistake.

Source

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

                        key.prepare(context);
                        val.prepare(context);
                    }
                });
            }
            relaxedOk = true;
        }

        //check how the object is constructed
        NonDefaultConstructorHolder nonDefaultConstructorHolder = null;
        DeferredParameter[] nonDefaultConstructorHandles = null;
        //used to resolve the parameter position for @RecordableConstructor
        Map<String, Integer> constructorParamNameMap = new HashMap<>();

        if (nonDefaultConstructors.containsKey(param.getClass())) {
            nonDefaultConstructorHolder = nonDefaultConstructors.get(param.getClass());
            List<Object> params = nonDefaultConstructorHolder.paramGenerator.apply(param);
            if (params.size() != nonDefaultConstructorHolder.constructor.getParameterCount()) {
                throw new RuntimeException("Unable to serialize " + param
                        + " as the wrong number of parameters were generated for "
                        + nonDefaultConstructorHolder.constructor);
            }
            int count = 0;
            nonDefaultConstructorHandles = new DeferredParameter[params.size()];
            Class<?>[] parameterTypes = nonDefaultConstructorHolder.constructor.getParameterTypes();
            for (int i = 0; i < params.size(); i++) {
                Object obj = params.get(i);
                nonDefaultConstructorHandles[i] = loadObjectInstance(obj, existing,
                        parameterTypes[count++], relaxedValidation);
            }
            extractConstructorParameterNames(nonDefaultConstructorHolder.constructor, constructorParamNameMap);
        } else if (classesToUseRecordableConstructor.contains(param.getClass())) {
            Constructor<?> current = null;
            int count = 0;
            for (var c : param.getClass().getConstructors()) {
                if (current == null || current.getParameterCount() < c.getParameterCount()) {
                    current = c;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Update the registered paramGenerator to return exactly one value per constructor parameter, in order
  2. Recompile against the current constructor signature (parameter count/types may have changed in a newer Quarkus or extension version)
  3. Add an assertion/unit test that params.size() == constructor.getParameterCount() for your generated class

Example fix

// before
holder.paramGenerator = obj -> List.of(obj.getName());
// after (ctor is Foo(String name, int size))
holder.paramGenerator = obj -> List.of(obj.getName(), obj.getSize());
Defensive patterns

Strategy: validation

Validate before calling

List<Object> params = holder.paramGenerator.apply(instance);
if (params.size() != holder.constructor.getParameterCount()) {
    throw new IllegalStateException("paramGenerator/constructor arity mismatch for "
        + holder.constructor.getDeclaringClass());
}

Type guard

boolean arityOk(Function<Object,List<Object>> gen, Constructor<?> c, Object o) {
    return gen.apply(o).size() == c.getParameterCount();
}

Try / catch

try {
    recorder.record(instance);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("wrong number of parameters")) {
        throw new IllegalStateException("Fix registered paramGenerator for " + instance.getClass(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Registering a non-default constructor for a class where the supplied paramGenerator function (e.g. via RecordingAnnotations/ConstructorParameterCustomizer or a returned non-serializable object with a RecordableConstructor) returns fewer or more values than constructor.getParameterCount(); commonly after the class gains a new constructor parameter while the generator was not updated.

Common situations: Extension code evolved: a Quarkus upgrade changed a config-class constructor signature while custom param generation logic in the extension was left stale; hand-written paramGenerator with a hardcoded list of values.

Related errors


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