{"record":{"id":"7ec19683b9cd88bd","repo":"gradle/gradle","slug":"could-not-generate-test-report-to-s","errorCode":null,"errorMessage":"Could not generate test report to '%s'.","messagePattern":"Could not generate test report to '(.+?)'\\.","errorType":"exception","errorClass":"GenericHtmlReportGenerationException","httpStatus":null,"severity":"error","filePath":"platforms/software/testing-base/src/main/java/org/gradle/api/internal/tasks/testing/report/generic/GenericHtmlTestReportGenerator.java","lineNumber":190,"sourceCode":"                            if (childTree.hasUsefulDetails()) {\n                                requestsBuilder.add(childTree);\n                            }\n                        } else {\n                            queueTree(queue, childTree, output);\n                        }\n                    }\n                    // This is mostly I/O, so run it unconstrained to allow more parallelism\n                    queue.addUnconstrained(new HtmlReportFileGenerator(\n                        shrink,\n                        requestsBuilder.build(),\n                        output,\n                        outputReaders,\n                        rootDisplayNames\n                    ));\n                }\n            }, reportsDirectory.toFile());\n        } catch (Exception e) {\n            throw new GenericHtmlReportGenerationException(String.format(\"Could not generate test report to '%s'.\", reportsDirectory), e);\n        }\n    }\n\n    private static String getDisplayName(TestTreeModel model, int rootIndex) {\n        List<PerRootInfo> perRootInfos = model.getPerRootInfo().get(rootIndex);\n        if (perRootInfos.isEmpty()) {\n            throw new IllegalStateException(\"Root model is missing display name info for root index \" + rootIndex);\n        }\n        if (perRootInfos.size() > 1) {\n            throw new IllegalStateException(\"Root model has multiple display name infos for root index \" + rootIndex + \": \" + Iterables.toString(perRootInfos));\n        }\n        return SerializableTestResult.getCombinedDisplayName(perRootInfos.get(0).getResults());\n    }\n\n    private static final class HtmlReportFileGenerator implements RunnableBuildOperation {\n        private final boolean shrink;\n        private final List<TestTreeModel> requests;\n        private final HtmlReportBuilder output;","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/testing-base/src/main/java/org/gradle/api/internal/tasks/testing/report/generic/GenericHtmlTestReportGenerator.java#L172-L208","documentation":"GenericHtmlTestReportGenerator.generateFiles wraps the whole generic HTML report generation in a try/catch and rethrows any Exception as GenericHtmlReportGenerationException formatted with the reports directory. It is an umbrella: the actionable failure is always the wrapped cause, ranging from path-length limits to I/O errors to report-model invariant violations.","triggerScenarios":"Nested UnshrinkableReportPathException when a report file path cannot fit the limit; IOException while deleting the old report or writing files into the reports directory; IllegalStateException from report model invariants (e.g. 'Root model is missing display name info'); failures reading output-events.bin from the result store.","commonSituations":"Deep build directory paths on Windows hitting path limits; read-only, locked, or full disk at build/reports/tests; leftover corrupt results from a previously killed build; report aggregation setups combining results produced by different Gradle versions.","solutions":["Unwrap and read getCause() — fix the specific nested exception (UnshrinkableReportPathException, IOException, invariant error) rather than the umbrella message","Delete build/reports/tests and build/test-results and re-run to eliminate corrupt leftovers from an aborted run","If the cause is the unshrinkable path: shorten the report directory, reduce test nesting/names, or set reports.html.required = false","Check disk space and permissions/locks (antivirus on Windows) on the reports directory"],"exampleFix":"// build.gradle.kts — stop HTML report generation from failing the build when it is not needed\ntasks.withType<Test>().configureEach {\n    reports.html.required.set(false)\n}","handlingStrategy":"try-catch","validationCode":"// Before enabling HTML reports, sanity-check the target directory\nFile reportsDir = testTask.getReports().getHtml().getOutputLocation().getAsFile().get();\nif (!reportsDir.exists() ? !reportsDir.mkdirs() : !reportsDir.isDirectory() || !reportsDir.canWrite()) {\n    throw new InvalidUserDataException(\"Cannot write test report to \" + reportsDir);\n}","typeGuard":null,"tryCatchPattern":"try { run test task } catch (GenericHtmlReportGenerationException e) { Throwable cause = e.getCause(); if (cause instanceof UnshrinkableReportPathException) { disable/shorten report } else { rethrow or fail with cause } } — always branch on the nested cause, never the umbrella message.","preventionTips":["Keep the reports directory short, writable, and on a disk with free space","Delete stale build/reports and build/test-results after aborted runs","Set reports.html.required = false on tasks whose HTML report nobody consumes"],"tags":["gradle","testing","html-report","report-generation","io"],"backgroundTag":"report-generation-failed","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}