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
- Update the registered paramGenerator to return exactly one value per constructor parameter, in order
- Recompile against the current constructor signature (parameter count/types may have changed in a newer Quarkus or extension version)
- 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
- Unit-test every registered paramGenerator against its constructor's parameter count
- Derive generator output from the constructor signature, not hardcoded lists
- Add a build-time assertion in the extension that validates generator arity
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
- Unable to determine the recordable constructor to use for ${
- Could not find parameters for constructor ${nonDefaultConstr
- Unable to serialize objects of type ${param.getClass()} to b
- Couldn't extract all parameters information for constructor
- Cannot serialise field '${i.getName()}' on object '${param}'
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1ed37a000977083b.
Report an issue: GitHub.