quarkusio/quarkus · error · RuntimeException

Could not find parameters for constructor ${nonDefaultConstr

Error message

Could not find parameters for constructor ${nonDefaultConstructorHolder.constructor} could not read field values ${constructorParamNameMap.keySet()}

What it means

For an object with a non-default constructor, the recorder maps each constructor parameter to a field/property value read from the instance. After reading all matching fields, any constructor parameters that were never matched remain in constructorParamNameMap, meaning the object cannot be reconstructed faithfully — so recording fails.

Source

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

                                            FieldDescriptor.of(param.getClass(), field.getName(), field.getType()),
                                            context.loadDeferred(out),
                                            context.loadDeferred(val));
                                }

                                @Override
                                public void prepare(MethodContext context) {
                                    val.prepare(context);
                                }
                            });
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        if (!constructorParamNameMap.isEmpty()) {
            throw new RuntimeException("Could not find parameters for constructor " + nonDefaultConstructorHolder.constructor
                    + " could not read field values " + constructorParamNameMap.keySet());
        }
        NonDefaultConstructorHolder finalNonDefaultConstructorHolder = nonDefaultConstructorHolder;
        DeferredParameter[] finalCtorHandles = nonDefaultConstructorHandles;

        //create a deferred value to represent the object itself. This allows the creation to be split
        //over multiple methods, which is important if this is a large object
        DeferredArrayStoreParameter objectValue = new DeferredArrayStoreParameter(param, expectedType) {
            @Override
            ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                ResultHandle out;
                //do the creation
                if (finalNonDefaultConstructorHolder != null) {
                    out = method.newInstance(
                            ofConstructor(finalNonDefaultConstructorHolder.constructor.getDeclaringClass(),
                                    finalNonDefaultConstructorHolder.constructor.getParameterTypes()),
                            Arrays.stream(finalCtorHandles).map(m -> context.loadDeferred(m))
                                    .toArray(ResultHandle[]::new));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Rename fields (or constructor params) so each constructor parameter matches a field name exactly
  2. Compile with -parameters so parameter names are available
  3. Register an explicit paramGenerator for the constructor so field matching is unnecessary

Example fix

// before
public Pool(int max) { this.size = max; } // 'max' has no matching field
// after
public Pool(int max) { this.max = max; } // field 'max' exists
Defensive patterns

Strategy: validation

Validate before calling

for (Parameter p : ctor.getParameters()) {
    if (!hasFieldOrProperty(clazz, p.getName())) {
        throw new IllegalStateException("Constructor param '" + p.getName()
            + "' of " + clazz + " has no matching field/property");
    }
}

Type guard

boolean ctorParamsMapToFields(Constructor<?> c) {
    Set<String> fields = new HashSet<>();
    for (Class<?> k = c.getDeclaringClass(); k != null; k = k.getSuperclass())
        Arrays.stream(k.getDeclaredFields()).forEach(f -> fields.add(f.getName()));
    return Arrays.stream(c.getParameters()).allMatch(p -> fields.contains(p.getName()));
}

Try / catch

try {
    recorder.record(value);
} catch (RuntimeException e) {
    if (String.valueOf(e.getMessage()).startsWith("Could not find parameters for constructor")) {
        throw new IllegalStateException("Align constructor param names with fields on " + value.getClass(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Recording a class whose constructor parameter names don't correspond to any instance field/getter (e.g. parameter named 'capacity' but field is 'size'); missing -parameters compilation info for some parameters; subclass hiding a field.

Common situations: Classes where constructor parameter names differ from field names (no canonical naming); classes compiled without -parameters; renamed fields without updating constructor usage.

Related errors


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