junit-team/junit5 · error · PreconditionViolationException

Launcher session has already been closed

Error message

Launcher session has already been closed

What it means

After LauncherSession.close(), the session swaps its Launcher for a ClosedLauncher singleton whose registerLauncherDiscoveryListeners(...) unconditionally throws PreconditionViolationException. Any attempt to register a discovery listener on a closed session is rejected.

Solutions

  1. Register listeners before closing the session, inside the session's lifetime (within the try-with-resources block).
  2. If you need a fresh session, open a new one via LauncherSessionFactory.openSession() and register on its Launcher.
  3. Track session state in your code and skip registration (or reopen) once closed.

Example fix

// before
try (var session = factory.openSession()) {
    Launcher l = session.getLauncher();
} // session closed
l.registerLauncherDiscoveryListeners(listener); // throws
// after
try (var session = factory.openSession()) {
    Launcher l = session.getLauncher();
    l.registerLauncherDiscoveryListeners(listener); // in scope
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure listener registration happens before closing the session
try (var session = factory.openSession()) {
    Launcher l = session.getLauncher();
    l.registerLauncherDiscoveryListeners(listener); // in scope
}

Try / catch

try {
    launcher.registerLauncherDiscoveryListeners(listener);
} catch (PreconditionViolationException e) {
    // session closed: open a new session and retry
}

Prevention

When it happens

Trigger: Calling launcher.registerLauncherDiscoveryListeners(...) on the Launcher obtained from a LauncherSession that has already been closed (session.close() ran, or the try-with-resources block exited).

Common situations: Try-with-resources on LauncherSessionFactory.openSession() where listener registration happens after the block; a long-lived holder that captures the Launcher and uses it after the session closes; a plugin/tool that opens a session, closes it, then registers listeners.

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/ed95cd8f45ac5911. Report an issue: GitHub.

Appendix: source

Thrown at junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/DefaultLauncherSession.java:109

			interceptor.close();
		}
	}

	@Override
	public NamespacedHierarchicalStore<Namespace> getStore() {
		return store;
	}

	private static class ClosedLauncher implements Launcher {

		static final ClosedLauncher INSTANCE = new ClosedLauncher();

		private ClosedLauncher() {
		}

		@Override
		public void registerLauncherDiscoveryListeners(LauncherDiscoveryListener... listeners) {
			throw new PreconditionViolationException("Launcher session has already been closed");
		}

		@Override
		public void registerTestExecutionListeners(TestExecutionListener... listeners) {
			throw new PreconditionViolationException("Launcher session has already been closed");
		}

		@Override
		public TestPlan discover(LauncherDiscoveryRequest launcherDiscoveryRequest) {
			throw new PreconditionViolationException("Launcher session has already been closed");
		}

		@Override
		public void execute(LauncherDiscoveryRequest launcherDiscoveryRequest, TestExecutionListener... listeners) {
			throw new PreconditionViolationException("Launcher session has already been closed");
		}

		@Override

View on GitHub (pinned to f070c699a0)