hibernate/hibernate-orm · error · SchemaManagementException
Could not build JDBC Connection context to drop schema on…
Error message
Could not build JDBC Connection context to drop schema on SessionFactory close
What it means
With hibernate.hbm2ddl.auto=create-drop the DROP is deferred until SessionFactory close (DelayedDropAction). At close, Hibernate rebuilds a JDBC context via JdbcServices.getBootstrapJdbcConnectionAccess(); if the configured connection provider exposes no bootstrap connection access (null), it cannot obtain a connection to run the drop and throws this SchemaManagementException from the shutdown path. It is a configuration incompatibility, not a network failure.
Solutions
- Switch hibernate.hbm2ddl.auto from create-drop to create or none in environments whose connection provider has no bootstrap JDBC access, and drop schema explicitly when needed.
- Run schema generation in a bootstrap phase that uses a plain DataSource/DriverManager-based connection provider, then disable hbm2ddl for the tenant-scoped runtime.
- Instead of delayed drop, generate a drop script once (SchemaExport, TargetType.SCRIPT) and apply it from CI/cleanup tooling.
Example fix
// before <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <!-- multi-tenant connection provider --> // after <property name="hibernate.hbm2ddl.auto" value="none"/> <!-- generate ddl at build time via SchemaExport and manage drops out-of-band -->
Defensive patterns
Strategy: validation
Validate before calling
JdbcServices jdbc = serviceRegistry.requireService(JdbcServices.class);
if (jdbc.getBootstrapJdbcConnectionAccess() == null) {
// create-drop cannot run its delayed drop here: switch it off before building the factory
cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, Action.NONE.getExternalName());
} Try / catch
try {
sessionFactory.close();
} catch (SchemaManagementException e) {
if (e.getMessage() != null && e.getMessage().contains("drop schema on SessionFactory close")) {
// delayed drop could not run; drop the schema out-of-band, then finish shutdown
} else { throw e; }
} Prevention
- Never ship create-drop outside isolated tests; prefer explicit scripts.
- For multi-tenant or user-supplied-connection setups, keep hbm2ddl disabled and manage schema with migration tooling.
- Smoke-test the full open/close lifecycle of the factory in the same configuration you deploy.
When it happens
Trigger: create-drop combined with a ConnectionProvider whose getBootstrapJdbcConnectionAccess() yields null: multi-tenant setups backed by a MultiTenantConnectionProvider, user-supplied connections, or custom connection providers that only serve tenant/user-scoped connections. The exception is thrown while the SessionFactory is closing, out of the JdbcContextDelayedDropImpl constructor.
Common situations: Multi-tenant applications that kept create-drop from a single-tenant prototype; Spring Boot tests wiring a tenant-aware DataSource into hbm2ddl; demos run with externally provided Connections; custom connection providers migrated from Hibernate 5 where this path behaved differently.
Related errors
- Bean Validation API was not available, but…
- Cannot unwrap to requested type
- Could not set provided connection
- entity class not found: " + className
- Error creating SQL 'create' commands for table '
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/85200f0954566bd1.
Report an issue: GitHub.
Appendix: source
Thrown at hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java:645
}
}
finally {
target.release();
}
}
private static class JdbcContextDelayedDropImpl implements JdbcContext {
private final ServiceRegistry serviceRegistry;
private final JdbcServices jdbcServices;
private final JdbcConnectionAccess jdbcConnectionAccess;
public JdbcContextDelayedDropImpl(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
this.jdbcServices = serviceRegistry.requireService( JdbcServices.class );
this.jdbcConnectionAccess = jdbcServices.getBootstrapJdbcConnectionAccess();
if ( jdbcConnectionAccess == null ) {
// todo : log or error?
throw new SchemaManagementException(
"Could not build JDBC Connection context to drop schema on SessionFactory close"
);
}
}
@Override
public JdbcConnectionAccess getJdbcConnectionAccess() {
return jdbcConnectionAccess;
}
@Override
public Dialect getDialect() {
return jdbcServices.getJdbcEnvironment().getDialect();
}
@Override
public SqlStatementLogger getSqlStatementLogger() {
return jdbcServices.getSqlStatementLogger();View on GitHub (pinned to fad1729dce)