{"record":{"id":"59238b247913a30b","repo":"hibernate/hibernate-orm","slug":"bootstrapcontext-is-no-longer-available","errorCode":null,"errorMessage":"BootstrapContext is no longer available","messagePattern":"BootstrapContext is no longer available","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java","lineNumber":545,"sourceCode":"\t}\n\n\t@Override\n\t@Nonnull\n\tpublic PlanningOptions getGraphPlanningOptions() {\n\t\treturn graphPlanningOptions;\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tclass IntegratorObserver implements SessionFactoryObserver {\n\t\tprivate final Integrator.Context context = new Integrator.Context() {\n\t\t\t@Override\n\t\t\tpublic ManagedBeanRegistry getManagedBeanRegistry() {\n\t\t\t\treturn SessionFactoryImpl.this.getManagedBeanRegistry();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic BootstrapContext getBootstrapContext() {\n\t\t\t\tthrow new IllegalStateException( \"BootstrapContext is no longer available\" );\n\t\t\t}\n\t\t};\n\t\tprivate final ArrayList<Integrator> integrators = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic void sessionFactoryClosed(SessionFactory factory) {\n\t\t\tfor ( var integrator : integrators ) {\n\t\t\t\tintegrator.disintegrate( SessionFactoryImpl.this, context );\n\t\t\t}\n\t\t\tintegrators.clear();\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate static Integrator.Context createIntegratorContext(BootstrapContext bootstrapContext) {\n\t\treturn () -> bootstrapContext;\n\t}\n","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java#L527-L563","documentation":"Hibernate hands each Integrator an Integrator.Context; on this implementation getBootstrapContext() deliberately throws IllegalStateException because the BootstrapContext (bootstrap-time services, classmate access, managed beans) is discarded once the SessionFactory is built. The context exposed by IntegratorObserver is only intended for disintegrate() callbacks at factory close. Any integrator that asks for the BootstrapContext after bootstrap will always get this error.","triggerScenarios":"An org.hibernate.integrator.spi.Integrator implementation calls context.getBootstrapContext() inside disintegrate(sessionFactory, context), or stores the Integrator.Context and calls getBootstrapContext() after SessionFactoryObserver.sessionFactoryClosed fires. Also hit by integrators ported from older Hibernate versions where disintegrate() used to receive a BootstrapContext parameter.","commonSituations":"Upgrading a custom integrator from Hibernate 5.x/6.0 to 6.2+/7.x where the disintegrate signature changed to Integrator.Context; third-party integrator libraries (auditing, multi-tenancy, metrics) that still touch bootstrap services at shutdown; integrators that resolve beans via BootstrapContext instead of caching them during integrate().","solutions":["Cache everything you need from BootstrapContext (ServiceRegistry, ManagedBeanRegistry, BeanContainer) in fields during integrate(); never call context.getBootstrapContext() in disintegrate()","If you need managed beans at shutdown, use context.getManagedBeanRegistry() which is still supported on this Context implementation","Upgrade the integrator library to a Hibernate 6.2+/7.x compatible build where the new Integrator.Context contract is respected","If you control the code, restructure the integrator so shutdown work only needs the SessionFactoryImplementor passed to disintegrate()"],"exampleFix":"// before\n@Override\npublic void disintegrate(SessionFactoryImplementor factory, Integrator.Context context) {\n    context.getBootstrapContext().getServiceRegistry(); // IllegalStateException\n}\n\n// after\nprivate ServiceRegistry serviceRegistry;\n\n@Override\npublic void integrate(Metadata metadata, BootstrapContext bootstrapContext,\n                       SessionFactoryImplementor sessionFactory) {\n    this.serviceRegistry = bootstrapContext.getServiceRegistry(); // capture at bootstrap\n}\n\n@Override\npublic void disintegrate(SessionFactoryImplementor factory, Integrator.Context context) {\n    // use the cached serviceRegistry; never call context.getBootstrapContext()\n}","handlingStrategy":"validation","validationCode":"// In your integrator, gate on a flag you control instead of probing the context\nprivate boolean bootstrapped;\n\n@Override\npublic void integrate(Metadata md, BootstrapContext ctx, SessionFactoryImplementor sf) {\n    this.captured = ctx.getServiceRegistry();\n    this.bootstrapped = true;\n}\n\n@Override\npublic void disintegrate(SessionFactoryImplementor sf, Integrator.Context ctx) {\n    if (!bootstrapped) return; // integrate never ran; do not touch bootstrap resources\n    // use `captured`, never ctx.getBootstrapContext()\n}","typeGuard":null,"tryCatchPattern":"try {\n    // integrator shutdown logic\n} catch (IllegalStateException e) {\n    // BootstrapContext is gone after bootstrap; fall back to data cached at integrate()\n    LOG.warn(\"bootstrap context unavailable at disintegrate; using cached state\", e);\n}","preventionTips":["Treat BootstrapContext as bootstrap-only: snapshot everything you need in integrate() and never store the context itself","Use Integrator.Context.getManagedBeanRegistry() for bean lookups at disintegrate() — it stays available","When upgrading Hibernate major versions, re-read the org.hibernate.integrator.spi.Integrator contract — signature and lifecycle guarantees change","Add an integration test that builds and closes a SessionFactory with your integrator to catch lifecycle regressions early"],"tags":["hibernate","integrator","lifecycle","bootstrap","shutdown"],"backgroundTag":"use-after-close","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}