{"id":"60a09509c1389b85","repo":"junit-team/junit5","slug":"d-configuration-errors-n-s","errorCode":null,"errorMessage":"%d configuration errors:%n%s","messagePattern":"(.+?) configuration errors:%n(.+?)","errorType":"exception","errorClass":"PreconditionViolationException","httpStatus":null,"severity":"error","filePath":"junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java","lineNumber":389,"sourceCode":"\t\t\t\tparameterDeclarationMapping.put(actualDeclaration, originalDeclaration);\n\t\t\t}\n\t\t}\n\t\treturn errors;\n\t}\n\n\tprivate static String parameterName(ParameterDeclaration actualDeclaration) {\n\t\treturn actualDeclaration.getParameterName().map(name -> \" '\" + name + \"'\").orElse(\"\");\n\t}\n\n\tprivate static <T> T configurationErrorOrSuccess(List<String> errors, Supplier<T> successfulResult) {\n\t\tif (errors.isEmpty()) {\n\t\t\treturn successfulResult.get();\n\t\t}\n\t\telse if (errors.size() == 1) {\n\t\t\tthrow new PreconditionViolationException(\"Configuration error: \" + errors.get(0) + \".\");\n\t\t}\n\t\telse {\n\t\t\tthrow new PreconditionViolationException(\"%d configuration errors:%n%s\".formatted(errors.size(),\n\t\t\t\terrors.stream().collect(joining(lineSeparator() + \"- \", \"- \", \"\"))));\n\t\t}\n\t}\n\n\tprivate static void validateIndexedParameters(\n\t\t\tNavigableMap<Integer, List<FieldParameterDeclaration>> indexedParameters, List<String> errors) {\n\n\t\tif (indexedParameters.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tindexedParameters.forEach(\n\t\t\t(index, declarations) -> validateIndexedParameterDeclarations(index, declarations, errors));\n\n\t\tfor (int index = 0; index <= indexedParameters.lastKey(); index++) {\n\t\t\tif (!indexedParameters.containsKey(index)) {\n\t\t\t\terrors.add(\"no field annotated with @Parameter(%d) declared\".formatted(index));\n\t\t\t}","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java#L371-L407","documentation":"Thrown by ResolverFacade.configurationErrorOrSuccess() when two or more validation errors are found during @ParameterizedClass field declaration or lifecycle method validation. The message includes the error count and a bulleted list of all errors, each on its own line. This aggregates multiple misconfigurations into a single exception so the developer can fix them all at once.","triggerScenarios":"Multiple simultaneous misconfigurations in a @ParameterizedClass: e.g., a final @Parameter field AND a duplicate @Parameter index, or a gap in indices AND a final field. Any combination of two or more errors from validateIndexedParameters, validateAggregatorParameters, or validateLifecycleMethodParameters.","commonSituations":"Bulk-adding multiple @Parameter fields with several mistakes at once — final fields, index gaps, duplicate indices. Combining @Parameter field issues with lifecycle method parameter incompatibilities in the same class.","solutions":["Read the full error list in the exception message — each error is prefixed with '- ' on its own line","Fix ALL listed errors, not just the first one, since the framework reports them together","Common fixes: remove 'final' from @Parameter fields, ensure sequential indices (0,1,2...), remove duplicate indices","Ensure aggregator fields (@AggregateWith or ArgumentsAccessor type) do not declare a @Parameter index"],"exampleFix":"// before\n@ParameterizedClass\n@CsvSource(\"1, 2, 3\")\nclass MyTest {\n    @Parameter(0) final int a; // error 1: final\n    @Parameter(0) int b;       // error 2: duplicate index 0\n    @Parameter(2) int c;       // error 3: gap (no index 1)\n}\n\n// after\n@ParameterizedClass\n@CsvSource(\"1, 2, 3\")\nclass MyTest {\n    @Parameter(0) int a;\n    @Parameter(1) int b;\n    @Parameter(2) int c;\n}","handlingStrategy":"validation","validationCode":"// Validate all @Parameter fields at once:\nstatic List<String> validateFields(Class<?> testClass) {\n    List<String> errors = new ArrayList<>();\n    Map<Integer, Field> indices = new TreeMap<>();\n    for (Field f : testClass.getDeclaredFields()) {\n        Parameter p = f.getAnnotation(Parameter.class);\n        if (p == null) continue;\n        if (Modifier.isFinal(f.getModifiers())) errors.add(f + \" is final\");\n        if (indices.containsKey(p.value())) errors.add(\"duplicate index \" + p.value());\n        indices.put(p.value(), f);\n    }\n    for (int i = 0; i < indices.size(); i++)\n        if (!indices.containsKey(i)) errors.add(\"missing index \" + i);\n    return errors;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fix ALL errors listed in the exception message, not just the first one","Review every @Parameter field: non-final, sequential indices, no duplicates","Use a static analysis check or unit test to validate @Parameter field declarations before running the suite","Keep @Parameter field declarations together at the top of the class for easy review"],"tags":["parameterized-class","field-injection","configuration","validation","junit-jupiter-params"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}