{"id":"d214662d979ae93c","repo":"junit-team/junit5","slug":"failed-to-create-forkjoinpool","errorCode":null,"errorMessage":"Failed to create ForkJoinPool","messagePattern":"Failed to create ForkJoinPool","errorType":"exception","errorClass":"JUnitException","httpStatus":null,"severity":"critical","filePath":"junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java","lineNumber":111,"sourceCode":"\t\tthis(configuration, TaskEventListener.NOOP);\n\t}\n\n\tForkJoinPoolHierarchicalTestExecutorService(ParallelExecutionConfiguration configuration,\n\t\t\tTaskEventListener taskEventListener) {\n\t\tforkJoinPool = createForkJoinPool(configuration);\n\t\tthis.taskEventListener = taskEventListener;\n\t\tparallelism = forkJoinPool.getParallelism();\n\t\tLoggerFactory.getLogger(getClass()).config(() -> \"Using ForkJoinPool with parallelism of \" + parallelism);\n\t}\n\n\tprivate ForkJoinPool createForkJoinPool(ParallelExecutionConfiguration configuration) {\n\t\ttry {\n\t\t\treturn new ForkJoinPool(configuration.getParallelism(), new WorkerThreadFactory(), null, false,\n\t\t\t\tconfiguration.getCorePoolSize(), configuration.getMaxPoolSize(), configuration.getMinimumRunnable(),\n\t\t\t\tconfiguration.getSaturatePredicate(), configuration.getKeepAliveSeconds(), TimeUnit.SECONDS);\n\t\t}\n\t\tcatch (Exception cause) {\n\t\t\tthrow new JUnitException(\"Failed to create ForkJoinPool\", cause);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Future<@Nullable Void> submit(TestTask testTask) {\n\t\tExclusiveTask exclusiveTask = new ExclusiveTask(testTask);\n\t\tif (!isAlreadyRunningInForkJoinPool()) {\n\t\t\t// ensure we're running inside the ForkJoinPool so we\n\t\t\t// can use ForkJoinTask API in invokeAll etc.\n\t\t\treturn forkJoinPool.submit(exclusiveTask);\n\t\t}\n\t\t// Limit the amount of queued work so we don't consume dynamic tests too eagerly\n\t\t// by forking only if the current worker thread's queue length is below the\n\t\t// desired parallelism. This optimistically assumes that the already queued tasks\n\t\t// can be stolen by other workers and the new task requires about the same\n\t\t// execution time as the already queued tasks. If the other workers are busy,\n\t\t// the parallelism is already at its desired level. If all already queued tasks\n\t\t// can be stolen by otherwise idle workers and the new task takes significantly","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/junit-team/junit5/blob/956246301e03d757539f7b76dd5a91f298637563/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java#L93-L129","documentation":"Thrown by ForkJoinPoolHierarchicalTestExecutorService.createForkJoinPool (line 104-113) when the ForkJoinPool constructor raises any Exception (IllegalArgumentException, etc.). It is wrapped in a JUnitException. The pool is built from a ParallelExecutionConfiguration derived from junit.platform.execution.parallel config parameters.","triggerScenarios":"Configuring parallel execution (junit.jupiter.execution.parallel.enabled=true) with invalid values: parallelism < 0, maxPoolSize < corePoolSize, minimumRunnable negative, or values exceeding JVM limits. ForkJoinPool's 7-arg constructor enforces several invariants and throws IllegalArgumentException on violations.","commonSituations":"Setting junit.jupiter.execution.parallel.config.fixed.parallelism to a huge/negative number; mismatched fixed.parallelism/fixed.max-pool-size; dynamic config strategy computing a bad configuration on a constrained CI box; very low-memory JVMs unable to allocate worker threads.","solutions":["Check and correct the parallel execution config in junit-platform.properties: ensure 0 <= parallelism, and corePoolSize <= maxPoolSize.","Read the caused-by exception (usually IllegalArgumentException naming the offending parameter) and fix that specific value.","Switch to the dynamic configuration strategy or lower parallelism to match available processors.","Validate Runtime.getRuntime().availableProcessors() and size parallelism relative to it."],"exampleFix":"// before (junit-platform.properties)\n// junit.jupiter.execution.parallel.enabled=true\n// junit.jupiter.execution.parallel.config.fixed.parallelism=-1\n// junit.jupiter.execution.parallel.config.fixed.max-pool-size=2\n\n// after\n// junit.jupiter.execution.parallel.enabled=true\n// junit.jupiter.execution.parallel.config.fixed.parallelism=4\n// junit.jupiter.execution.parallel.config.fixed.max-pool-size=8","handlingStrategy":"validation","validationCode":"int parallelism = Math.max(1, Runtime.getRuntime().availableProcessors());\nint maxPool = Math.max(parallelism * 2, parallelism);\n// then set in junit-platform.properties or build ParallelExecutionConfiguration accordingly","typeGuard":"static boolean isValidParallelConfig(ParallelExecutionConfiguration c) {\n    return c.getParallelism() >= 0\n        && c.getCorePoolSize() >= 1\n        && c.getMaxPoolSize() >= c.getCorePoolSize()\n        && c.getMinimumRunnable() >= 0;\n}","tryCatchPattern":"try {\n    return new ForkJoinPoolHierarchicalTestExecutorService(config);\n} catch (JUnitException e) {\n    throw new IllegalStateException(\"invalid parallel config; check junit.platform.execution.parallel.*\", e.getCause());\n}","preventionTips":["Bound parallelism by available processors and keep max-pool-size >= core-pool-size >= parallelism.","Validate junit-platform.properties parallel settings in a startup check.","Read the caused-by IllegalArgumentException to find the offending parameter."],"tags":["junit-platform","parallel-execution","fork-join-pool","configuration","threading"],"analyzedSha":"956246301e03d757539f7b76dd5a91f298637563","analyzedAt":"2026-08-04T19:25:17.049Z","schemaVersion":2}