{"record":{"id":"a4871b027dbb10df","repo":"hibernate/hibernate-orm","slug":"should-not-register-strategies-during-shutdown","errorCode":null,"errorMessage":"Should not register strategies during shutdown","messagePattern":"Should not register strategies during shutdown","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorImpl.java","lineNumber":279,"sourceCode":"\t\t}\n\t}\n\n\tprivate class StartupContributions implements NamedStrategyContributions {\n\t\t@Override\n\t\tpublic <T> void contributeStrategyImplementor(Class<T> strategy, Class<? extends T> implementation, String... names) {\n\t\t\tcontributeImplementation( strategy, implementation, names );\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> void removeStrategyImplementor(Class<T> strategy, Class<? extends T> implementation) {\n\t\t\tremoveImplementation( strategy, implementation );\n\t\t}\n\t}\n\n\tprivate class ShutdownContributions extends StartupContributions {\n\t\t@Override\n\t\tpublic <T> void contributeStrategyImplementor(Class<T> strategy, Class<? extends T> implementation, String... names) {\n\t\t\tthrow new IllegalStateException( \"Should not register strategies during shutdown\" );\n\t\t}\n\t}\n\n\t@Override @Deprecated(forRemoval = true)\n\tpublic <T> void registerStrategyImplementor(Class<T> strategy, String name, Class<? extends T> implementation) {\n\t\tcontributeImplementation( strategy, implementation, name );\n\t}\n\n\t@Override @Deprecated(forRemoval = true)\n\tpublic <T> void unRegisterStrategyImplementor(Class<T> strategy, Class<? extends T> implementation) {\n\t\tremoveImplementation( strategy, implementation );\n\t}\n}\n","sourceCodeStart":261,"sourceCodeEnd":293,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorImpl.java#L261-L293","documentation":"Once shutdown begins, StrategySelectorImpl swaps its contribution handler to ShutdownContributions, whose contributeStrategyImplementor() throws IllegalStateException - registering new strategies into a registry being torn down would corrupt the shutdown sequence. The remove path still works; only new contributions are rejected.","triggerScenarios":"Any code registering a strategy (addStrategyImplementor or the deprecated registerStrategyImplementor) that executes during or after registry destroy - e.g., a shutdown hook, an integration reacting to shutdown events, or a race between application shutdown and dynamic registration.","commonSituations":"Integrations that lazily register strategies on first use and get touched during shutdown; background threads still registering while the SessionFactory closes; custom lifecycle code mixing registration with teardown.","solutions":["Guard every dynamic registration with a check that the owning registry is still active before contributing","Ensure strategy registration completes fully during startup, not from shutdown hooks or listeners","Cancel or join registration threads before closing the SessionFactory/registry"],"exampleFix":"// before\nRuntime.getRuntime().addShutdownHook(new Thread(() ->\n    strategySelector.addStrategyImplementor(Dialect.class, MyDialect.class, \"mine\"))); // during shutdown -> throws\n\n// after\nstrategySelector.addStrategyImplementor(Dialect.class, MyDialect.class, \"mine\"); // register at startup","handlingStrategy":"validation","validationCode":"// Guard every dynamic registration against registry liveness\nif (!serviceRegistry.isActive()) {\n    log.debug(\"Registry shutting down - skipping strategy registration for {}\", strategy);\n    return;\n}\nstrategySelector.addStrategyImplementor(strategy, implementation, names);","typeGuard":null,"tryCatchPattern":"try {\n    strategySelector.addStrategyImplementor(strategy, implementation, names);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"during shutdown\")) {\n        // registration raced with shutdown: drop it; the registry is going away anyway\n        return;\n    }\n    throw e;\n}","preventionTips":["Register all strategies eagerly during startup; never from shutdown hooks or listeners","Check registry.isActive() before any dynamic registration","Stop registration-producing threads before closing the SessionFactory"],"tags":["hibernate","strategy","lifecycle","shutdown","internal-api"],"backgroundTag":"invalid-lifecycle-transition","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}