hibernate/hibernate-orm · error · SessionException

Cannot redefine the read-only mode on a child session if the

Error message

Cannot redefine the read-only mode on a child session if the connection is reused

What it means

Same guard as the tenant check in SharedSessionBuilderImpl.open(): when a child session shares the parent's transaction coordinator (and physical connection) under multi-tenancy, Hibernate also refuses to change the read-only mode. Calling readOnly(...) on the shared-session builder sets readOnlyChanged, and open() throws because the shared connection/transaction is already in the parent's read-only mode.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java:72

	@Override
	@Nonnull
	public SharedSessionBuilderImplementor withOption(EntityManager.CreationOption option) {
		options.apply( option );
		return this;
	}

	@Override
	@Nonnull
	public SessionImplementor open() {
		CORE_LOGGER.openingSession( options.getTenantIdentifierValue() );
		if ( original.getFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) {
			if ( options.isTransactionCoordinatorShared() ) {
				if ( tenantIdChanged ) {
					throw new SessionException(
							"Cannot redefine the tenant identifier on a child session if the connection is reused" );
				}
				if ( readOnlyChanged ) {
					throw new SessionException(
							"Cannot redefine the read-only mode on a child session if the connection is reused" );
				}
			}
		}
		return createSession( options );
	}

	@Override
	@Nonnull
	public SessionImplementor openSession() {
		return open();
	}

	@Override
	@Nonnull
	public SharedSessionBuilderImplementor tenantIdentifier(Object tenantIdentifier) {
		super.tenantIdentifier( tenantIdentifier );
		tenantIdChanged = true;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the .readOnly(...) call from the shared-session builder and keep the parent's mode.
  2. Set the read-only mode you need on the parent session before deriving the child.
  3. Open an independent session (factory.openSession()) instead of sharing when read/write semantics must differ.
  4. Use session.setDefaultReadOnly()/setReadOnly(entity, ...) on the original session rather than redefining it on a shared child.

Example fix

// before - child shares connection but flips read-only -> SessionException
Session child = parent.sessionWithOptions()
        .connection()
        .readOnly(true)        // different from parent's mode
        .openSession();
// after - apply the mode on the parent, then share
parent.setDefaultReadOnly(true);
Session child = parent.sessionWithOptions().connection().openSession();
Defensive patterns

Strategy: validation

Validate before calling

// Only derive a shared child session when the read-only mode will not change
boolean sameReadOnly = parentSession.isDefaultReadOnly();
SessionBuilder<?> b = parentSession.sessionWithOptions().connection();
// do NOT call b.readOnly(...) with a different value; keep parent's mode
return b.openSession();

Try / catch

catch (SessionException e) {
    if (e.getMessage() != null && e.getMessage().contains("read-only mode on a child session")) {
        return factory.openSession(); // independent session, its own mode allowed
    }
    throw e;
}

Prevention

When it happens

Trigger: session.sessionWithOptions()...openSession() with transaction/connection sharing and multi-tenancy enabled, where .readOnly(true) or .readOnly(false) is called with a value different from the original session's read-only setting.

Common situations: Read-only report sessions derived from a read-write request session; utility code that 'optimizes' child sessions with .readOnly(true); refactoring code so that a shared builder now toggles read-only.

Related errors


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