hibernate/hibernate-orm · error · ResourceClosedException

Logical connection is closed

Error message

Logical connection is closed

What it means

ResourceClosedException from LogicalConnectionManagedImpl.manualDisconnect(): session.disconnect() was invoked after the logical connection was already closed. It is a lifecycle usage error — you cannot disconnect an already-closed session; the disconnect operation itself is what failed, no JDBC work was attempted.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/LogicalConnectionManagedImpl.java:181

	}

	@Override
	public void afterTransaction() {
		super.afterTransaction();
		if ( resolvedConnectionReleaseMode() != ON_CLOSE ) {
			// NOTE: we check for !ON_CLOSE here (rather than AFTER_TRANSACTION) to also catch:
			// - AFTER_STATEMENT cases that were circumvented due to held resources
			// - BEFORE_TRANSACTION_COMPLETION cases that were circumvented because a rollback occurred
			//   (we don't get a beforeTransactionCompletion event on rollback).
			CONNECTION_LOGGER.initiatingConnectionReleaseAfterTransaction( hashCode() );
			releaseConnectionIfNeeded();
		}
	}

	@Override
	public Connection manualDisconnect() {
		if ( closed ) {
			throw new ResourceClosedException( "Logical connection is closed" );
		}
		final var connection = physicalConnection;
		releaseConnectionIfNeeded();
		return connection;
	}

	@Override
	public void manualReconnect(@Nonnull Connection suppliedConnection) {
		if ( closed ) {
			throw new ResourceClosedException( "Logical connection is closed" );
		}
		throw new IllegalStateException( "Cannot manually reconnect unless Connection was originally supplied by user" );
	}

	private Connection acquire() {
		final var eventHandler = getJdbcSessionContext().getEventHandler();
		eventHandler.jdbcConnectionAcquisitionStart();
		try {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Guard the call: if (session.isOpen()) session.disconnect();
  2. Drop manual disconnect/reconnect entirely and let hibernate.connection.handling_mode manage acquisition/release
  3. Ensure close() happens exactly once, in the single place that owns the session lifecycle

Example fix

// before
finally { session.disconnect(); } // throws ResourceClosedException if already closed

// after
finally {
  if (session.isOpen()) session.disconnect();
  if (session.isOpen()) session.close();
}
Defensive patterns

Strategy: validation

Validate before calling

if (session.isOpen()) {
  session.disconnect();
}

Type guard

static boolean isUsable(org.hibernate.Session s) {
  return s != null && s.isOpen();
}

Try / catch

catch (org.hibernate.ResourceClosedException e) {
  // in cleanup paths this is harmless: the session is already closed; log at debug and continue
}

Prevention

When it happens

Trigger: session.disconnect() after session.close(); unconditional disconnect() in a finally block that also (or earlier elsewhere) closed the session; double disconnect in layered cleanup code.

Common situations: Old long-conversation disconnect/reconnect recipes (Hibernate 2/3 era) combined with container- or Spring-managed session closing; finally blocks calling disconnect() regardless of prior failure paths that already closed the session.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/ccbffeb7736440c9. Report an issue: GitHub.