hibernate/hibernate-orm · error · HibernateException
Row-level security enabled, but no tenant identifier specifi
Error message
Row-level security enabled, but no tenant identifier specified
What it means
Row-level security is switched on for this factory (SessionFactoryOptions rowLevelSecurityEnabled), so when a session first uses its physical connection setUpRowLevelSecurity() must bind the tenant onto it (RowLevelSecurity.setTenantIdentifier or a dedicated DB user in user-mode). getTenantIdentifierValue() returned null, so the connection cannot be pinned to a tenant partition and Hibernate aborts rather than run with unrestricted row visibility.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java:1268
public void afterTransactionBegin() {
setUpRowLevelSecurity();
}
private RowLevelSecurity getRowLevelSecurity() {
return getJdbcServices().getDialect().getRowLevelSecurity();
}
private void setUpRowLevelSecurity() {
if ( rowLevelSecurityEnabled ) {
setUpRowLevelSecurity( getJdbcCoordinator().getLogicalConnection().getPhysicalConnection() );
}
}
private void setUpRowLevelSecurity(Connection connection) {
if ( rowLevelSecurityEnabled ) {
final Object tenantIdentifier = getTenantIdentifierValue();
if ( tenantIdentifier == null ) {
throw new HibernateException( "Row-level security enabled, but no tenant identifier specified" );
}
if ( !useDatabaseUserForRowLevelSecurity() ) {
final var resolver = factory.getCurrentTenantIdentifierResolver();
final boolean root = resolver != null && resolver.isRoot( tenantIdentifier );
try {
getRowLevelSecurity()
.setTenantIdentifier( connection, getTenantIdentifier(), root );
}
catch (SQLException e) {
throw getJdbcServices().getSqlExceptionHelper()
.convert( e, "Unable to set row-level security tenant identifier" );
}
}
}
}
private boolean useDatabaseUserForRowLevelSecurity() {View on GitHub (pinned to fad1729dce)
Solutions
- Provide the tenant for every session exactly as for multi-tenancy: withOptions().tenantIdentifier(...) on open, or a CurrentTenantIdentifierResolver that always resolves a value (see error 1540).
- If row-level security was enabled by accident or is not needed for this factory, remove the setting.
- In database-user mode, also verify the tenant-to-user mapping exists so useDatabaseUserForRowLevelSecurity() can switch users.
Example fix
// before Session s = sf.openSession(); // row-level security enabled, no tenant s.find(Customer.class, 1L); // HibernateException // after Session s = sf.withOptions().tenantIdentifier(tenantContext.get()).openSession();
Defensive patterns
Strategy: validation
Validate before calling
Object tenant = tenantContext.get();
if (tenant == null) {
throw new IllegalStateException("Row-level security requires a tenant on every session");
}
try (Session s = sf.withOptions().tenantIdentifier(tenant).openSession()) { ... } Prevention
- Reuse the multi-tenancy tenant infrastructure when enabling row-level security
- Cover system jobs with an explicit root/system tenant if the resolver supports isRoot()
- Add a startup self-check that opens and queries one session per configured mode
When it happens
Trigger: Enabling the row-level security setting (e.g., hibernate.row_level_security) while opening sessions/EntityManagers without a tenant identifier and without a CurrentTenantIdentifierResolver that yields one; typically fails on the first statement that acquires the physical connection.
Common situations: Adopting Hibernate 7 row-level security (PostgreSQL/Oracle RLS integration) without porting over the tenant-context infrastructure; system/background sessions that have no tenant; resolver wired only for web request threads.
Related errors
- all @TenantId fields must have the same type: <parameterType
- @TenantId attribute must be mapped to a single column or for
- assigned tenant id differs from current tenant id [{} != {}]
- SessionFactory configured for multi-tenancy, but no tenant i
- Unable to access JDBC metadata
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c9ebf22a165f92cf.
Report an issue: GitHub.