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 significantly

View on GitHub (pinned to 956246301e)

Solutions

  1. Check and correct the parallel execution config in junit-platform.properties: ensure 0 <= parallelism, and corePoolSize <= maxPoolSize.
  2. Read the caused-by exception (usually IllegalArgumentException naming the offending parameter) and fix that specific value.
  3. Switch to the dynamic configuration strategy or lower parallelism to match available processors.
  4. 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

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


AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04). Data as JSON: /data/errors/d214662d979ae93c.json. Report an issue: GitHub.