{"record":{"id":"4b43f0cc98ad77d8","repo":"quarkusio/quarkus","slug":"could-not-find-parameters-for-constructor-nondef","errorCode":null,"errorMessage":"Could not find parameters for constructor ${nonDefaultConstructorHolder.constructor} could not read field values ${constructorParamNameMap.keySet()}","messagePattern":"Could not find parameters for constructor (.+?) could not read field values (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java","lineNumber":1548,"sourceCode":"                                            FieldDescriptor.of(param.getClass(), field.getName(), field.getType()),\n                                            context.loadDeferred(out),\n                                            context.loadDeferred(val));\n                                }\n\n                                @Override\n                                public void prepare(MethodContext context) {\n                                    val.prepare(context);\n                                }\n                            });\n                        }\n                    } catch (Exception e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            }\n        }\n        if (!constructorParamNameMap.isEmpty()) {\n            throw new RuntimeException(\"Could not find parameters for constructor \" + nonDefaultConstructorHolder.constructor\n                    + \" could not read field values \" + constructorParamNameMap.keySet());\n        }\n        NonDefaultConstructorHolder finalNonDefaultConstructorHolder = nonDefaultConstructorHolder;\n        DeferredParameter[] finalCtorHandles = nonDefaultConstructorHandles;\n\n        //create a deferred value to represent the object itself. This allows the creation to be split\n        //over multiple methods, which is important if this is a large object\n        DeferredArrayStoreParameter objectValue = new DeferredArrayStoreParameter(param, expectedType) {\n            @Override\n            ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {\n                ResultHandle out;\n                //do the creation\n                if (finalNonDefaultConstructorHolder != null) {\n                    out = method.newInstance(\n                            ofConstructor(finalNonDefaultConstructorHolder.constructor.getDeclaringClass(),\n                                    finalNonDefaultConstructorHolder.constructor.getParameterTypes()),\n                            Arrays.stream(finalCtorHandles).map(m -> context.loadDeferred(m))\n                                    .toArray(ResultHandle[]::new));","sourceCodeStart":1530,"sourceCodeEnd":1566,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L1530-L1566","documentation":"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.","triggerScenarios":"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.","commonSituations":"Classes where constructor parameter names differ from field names (no canonical naming); classes compiled without -parameters; renamed fields without updating constructor usage.","solutions":["Rename fields (or constructor params) so each constructor parameter matches a field name exactly","Compile with -parameters so parameter names are available","Register an explicit paramGenerator for the constructor so field matching is unnecessary"],"exampleFix":"// before\npublic Pool(int max) { this.size = max; } // 'max' has no matching field\n// after\npublic Pool(int max) { this.max = max; } // field 'max' exists","handlingStrategy":"validation","validationCode":"for (Parameter p : ctor.getParameters()) {\n    if (!hasFieldOrProperty(clazz, p.getName())) {\n        throw new IllegalStateException(\"Constructor param '\" + p.getName()\n            + \"' of \" + clazz + \" has no matching field/property\");\n    }\n}","typeGuard":"boolean ctorParamsMapToFields(Constructor<?> c) {\n    Set<String> fields = new HashSet<>();\n    for (Class<?> k = c.getDeclaringClass(); k != null; k = k.getSuperclass())\n        Arrays.stream(k.getDeclaredFields()).forEach(f -> fields.add(f.getName()));\n    return Arrays.stream(c.getParameters()).allMatch(p -> fields.contains(p.getName()));\n}","tryCatchPattern":"try {\n    recorder.record(value);\n} catch (RuntimeException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Could not find parameters for constructor\")) {\n        throw new IllegalStateException(\"Align constructor param names with fields on \" + value.getClass(), e);\n    }\n    throw e;\n}","preventionTips":["Name constructor parameters identically to the fields they initialize","Compile with -parameters so names are visible to the recorder","Provide an explicit paramGenerator when naming conventions can't hold"],"tags":["quarkus","bytecode-recording","constructor"],"backgroundTag":"constructor-parameter-field-mapping-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}