junit-team/junit5 · critical · JUnitException
Failed to create ForkJoinPool
Error message
Failed to create ForkJoinPool
What it means
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.
Source
Thrown at junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ForkJoinPoolHierarchicalTestExecutorService.java:111
this(configuration, TaskEventListener.NOOP);
}
ForkJoinPoolHierarchicalTestExecutorService(ParallelExecutionConfiguration configuration,
TaskEventListener taskEventListener) {
forkJoinPool = createForkJoinPool(configuration);
this.taskEventListener = taskEventListener;
parallelism = forkJoinPool.getParallelism();
LoggerFactory.getLogger(getClass()).config(() -> "Using ForkJoinPool with parallelism of " + parallelism);
}
private ForkJoinPool createForkJoinPool(ParallelExecutionConfiguration configuration) {
try {
return new ForkJoinPool(configuration.getParallelism(), new WorkerThreadFactory(), null, false,
configuration.getCorePoolSize(), configuration.getMaxPoolSize(), configuration.getMinimumRunnable(),
configuration.getSaturatePredicate(), configuration.getKeepAliveSeconds(), TimeUnit.SECONDS);
}
catch (Exception cause) {
throw new JUnitException("Failed to create ForkJoinPool", cause);
}
}
@Override
public Future<@Nullable Void> submit(TestTask testTask) {
ExclusiveTask exclusiveTask = new ExclusiveTask(testTask);
if (!isAlreadyRunningInForkJoinPool()) {
// ensure we're running inside the ForkJoinPool so we
// can use ForkJoinTask API in invokeAll etc.
return forkJoinPool.submit(exclusiveTask);
}
// Limit the amount of queued work so we don't consume dynamic tests too eagerly
// by forking only if the current worker thread's queue length is below the
// desired parallelism. This optimistically assumes that the already queued tasks
// can be stolen by other workers and the new task requires about the same
// execution time as the already queued tasks. If the other workers are busy,
// the parallelism is already at its desired level. If all already queued tasks
// can be stolen by otherwise idle workers and the new task takes significantlyView on GitHub (pinned to 956246301e)
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.
Example fix
// before (junit-platform.properties) // junit.jupiter.execution.parallel.enabled=true // junit.jupiter.execution.parallel.config.fixed.parallelism=-1 // junit.jupiter.execution.parallel.config.fixed.max-pool-size=2 // after // junit.jupiter.execution.parallel.enabled=true // junit.jupiter.execution.parallel.config.fixed.parallelism=4 // junit.jupiter.execution.parallel.config.fixed.max-pool-size=8
Defensive patterns
Strategy: validation
Validate before calling
int parallelism = Math.max(1, Runtime.getRuntime().availableProcessors()); int maxPool = Math.max(parallelism * 2, parallelism); // then set in junit-platform.properties or build ParallelExecutionConfiguration accordingly
Type guard
static boolean isValidParallelConfig(ParallelExecutionConfiguration c) {
return c.getParallelism() >= 0
&& c.getCorePoolSize() >= 1
&& c.getMaxPoolSize() >= c.getCorePoolSize()
&& c.getMinimumRunnable() >= 0;
} Try / catch
try {
return new ForkJoinPoolHierarchicalTestExecutorService(config);
} catch (JUnitException e) {
throw new IllegalStateException("invalid parallel config; check junit.platform.execution.parallel.*", e.getCause());
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Task was deferred but should have been executed synchronousl
- Not on a worker thread
- Could not add entry to the queue for task: ${entry.task}
- Cannot override the standard style 'NONE'
- Could not read color palette properties
AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04).
Data as JSON: /data/errors/d214662d979ae93c.json.
Report an issue: GitHub.