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
- Register listeners before closing the session, inside the session's lifetime (within the try-with-resources block).
- If you need a fresh session, open a new one via LauncherSessionFactory.openSession() and register on its Launcher.
- 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
- Register all listeners inside the session try-with-resources block.
- Do not call launcher methods after session.close().
- Open a fresh session per independent run.
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
- Unsupported execution status
- Failed to initialize XML events writer
- Filter [ ] must implement , , or .
- Invalid LauncherPhase
- OutputDirectoryCreator not available; probably due to…
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");
}
@OverrideView on GitHub (pinned to f070c699a0)