junit-team/junit5 · error · JUnitException

Failed to close extension context

Error message

Failed to close extension context

What it means

Thrown when closing the JupiterEngineExecutionContext at teardown: if the ExtensionContext implements AutoCloseable, its close() method is invoked and any Exception it raises is wrapped into a JUnitException. This surfaces failures from extension context lifecycle cleanup (closing stores, extension-scoped resources).

Solutions

  1. Inspect getCause() for the underlying close() exception and fix the resource's close method (close defensively, swallow/log secondary errors).
  2. Make your Store.CloseableResource implementations idempotent and silent on the second close.
  3. Use try-with-resources inside test bodies rather than relying on Store cleanup for resources that can fail.

Example fix

// before
context.getStore(NAMESPACE).put("conn", new CloseableResource() {
    @Override public void close() throws Throwable { connection.close(); } // may throw
});
// after
context.getStore(NAMESPACE).put("conn", new CloseableResource() {
    @Override public void close() {
        try { connection.close(); } catch (SQLException e) { log.warn("close failed", e); }
    }
});
Defensive patterns

Strategy: try-catch

Try / catch

try {
    context.close();
} catch (JUnitException e) {
    Throwable cause = e.getCause();
    log.error("extension context close failed: {}", cause);
    throw e;
}

Prevention

When it happens

Trigger: JupiterEngineExecutionContext.close() calls ((AutoCloseable) extensionContext).close() and the close() throws - e.g. an extension registered a CloseableResource in the Store whose close() failed, or the extension context's own cleanup (store disposal) raised.

Common situations: Extension stores a resource (file handle, DB connection, mock control) via ExtensionContext.Store.put(key, CloseableResource) and that resource's close() throws IOException; cleanup-after-failure path where the test already threw and cleanup also fails.

Related errors


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

Appendix: source

Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java:54

	private boolean beforeAllMethodsExecuted = false;

	public JupiterEngineExecutionContext(EngineExecutionListener executionListener, JupiterConfiguration configuration,
			LauncherStoreFacade launcherStoreFacade) {
		this(new State(executionListener, configuration, launcherStoreFacade));
	}

	private JupiterEngineExecutionContext(State state) {
		this.state = state;
	}

	public void close() throws Exception {
		ExtensionContext extensionContext = getExtensionContext();
		if (extensionContext instanceof @SuppressWarnings("resource") AutoCloseable closeable) {
			try {
				closeable.close();
			}
			catch (Exception e) {
				throw new JUnitException("Failed to close extension context", e);
			}
		}
	}

	public EngineExecutionListener getExecutionListener() {
		return this.state.executionListener;
	}

	public JupiterConfiguration getConfiguration() {
		return this.state.configuration;
	}

	public LauncherStoreFacade getLauncherStoreFacade() {
		return this.state.launcherStoreFacade;
	}

	public TestInstancesProvider getTestInstancesProvider() {
		return requireNonNull(this.state.testInstancesProvider);

View on GitHub (pinned to f070c699a0)