hibernate/hibernate-orm · error · SessionException

Cannot redefine the tenant identifier on a child session if

Error message

Cannot redefine the tenant identifier on a child session if the connection is reused

What it means

When you derive a child session from an existing one via session.sessionWithOptions(), the builder can share the parent's transaction coordinator (and therefore its physical connection). If multi-tenancy is enabled and the tenant identifier was changed on the builder (tenantIdentifier with a different value sets tenantIdChanged), Hibernate refuses to open the child session: the shared connection is already bound to the original tenant, so a different tenant on the same connection would break tenant isolation.

Source

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

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// SharedSessionBuilder

	@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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Do not change the tenant on a child session that shares the parent's connection - drop the .tenantIdentifier(...) call if the same tenant is intended.
  2. Open a completely separate session (factory.openSession(tenantId)) for the other tenant so it gets its own connection from the tenant connection provider.
  3. Stop sharing the transaction coordinator on the builder (do not call .connection()/.transaction() sharing options) if you truly need a different tenant in the same thread.
  4. Review the design: cross-tenant work on a shared connection is exactly what this guard prevents.

Example fix

// before - shares parent connection but switches tenant -> SessionException
try (Session child = requestSession.sessionWithOptions()
        .connection()                      // reuse parent connection
        .tenantIdentifier("tenant-b")      // different tenant
        .openSession()) { ... }
// after - independent session gets its own connection for the tenant
try (Session other = sessionFactory.openSession(tenantBId)) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Before opening a shared child session, assert the tenant is unchanged
if (factory.getSessionFactoryOptions().isMultiTenancyEnabled()
        && !Objects.equals(desiredTenant, parentSession.getTenantIdentifierValue())) {
    // must NOT share the parent's connection/transaction with another tenant
    return factory.openSession(desiredTenant);
}
return parentSession.sessionWithOptions().connection().openSession();

Try / catch

catch (SessionException e) {
    if (e.getMessage() != null && e.getMessage().contains("tenant identifier on a child session")) {
        // recover by opening an independent session for the target tenant
        return factory.openSession(desiredTenant);
    }
    throw e;
}

Prevention

When it happens

Trigger: session.sessionWithOptions()...openSession() while sharing the transaction (the default when reusing the connection/transaction), with multi-tenancy enabled (MultiTenantConnectionProvider configured), and .tenantIdentifier(...) called with a value different from the parent session's tenant.

Common situations: Background jobs that open a worker session from a request session but switch tenants; incorrect assumption that sessionWithOptions() creates an independent connection; DATABASE/SHEMA/SCHEMA multi-tenant setups where the tenant decides which connection/schema is used.

Related errors


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