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();
}
@OverrideView on GitHub (pinned to fad1729dce)
Solutions
- 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.
- Open a completely separate session (factory.openSession(tenantId)) for the other tenant so it gets its own connection from the tenant connection provider.
- 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.
- 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
- Treat sessionWithOptions().connection() as 'same tenant, same mode only'.
- Encapsulate child-session creation in one helper that compares tenant ids first.
- Give each tenant its own session from the factory rather than reusing a parent connection.
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
- Cannot redefine the read-only mode on a child session if the
- Cannot redefine the tenant identifier on a child session if
- SessionFactory configured for multi-tenancy, but no tenant i
- MySQL does not support dropping creating/dropping schemas in
- all @TenantId fields must have the same type: <parameterType
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f34a4075df8943d5.
Report an issue: GitHub.