apache/dubbo · critical · IllegalStateException
FrameworkModel is destroyed
Error message
FrameworkModel is destroyed
What it means
Thrown by FrameworkModel.checkDestroyed() (a private guard invoked before mutating the model). It signals that the FrameworkModel has already completed its destroy lifecycle, so any attempt to obtain the default application model (defaultApplication()) or register a new application (addApplication()) is refused. The model tree is single-use: once destroyed it cannot be revived, and a fresh FrameworkModel must be created instead.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java:295
void tryDestroyProtocols() {
synchronized (instLock) {
if (pubApplicationModels.size() == 0) {
notifyProtocolDestroy();
}
}
}
void tryDestroy() {
synchronized (instLock) {
if (pubApplicationModels.size() == 0) {
destroy();
}
}
}
private void checkDestroyed() {
if (isDestroyed()) {
throw new IllegalStateException("FrameworkModel is destroyed");
}
}
private void resetDefaultAppModel() {
synchronized (instLock) {
if (this.defaultAppModel != null && !this.defaultAppModel.isDestroyed()) {
return;
}
ApplicationModel oldDefaultAppModel = this.defaultAppModel;
if (pubApplicationModels.size() > 0) {
this.defaultAppModel = pubApplicationModels.get(0);
} else {
this.defaultAppModel = null;
}
if (defaultInstance == this && oldDefaultAppModel != this.defaultAppModel) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Reset global default application from " + safeGetModelDesc(oldDefaultAppModel) + " to "
+ safeGetModelDesc(this.defaultAppModel));View on GitHub (pinned to 3a3043227f)
Solutions
- Do not reuse a destroyed FrameworkModel; create a new instance via `new FrameworkModel()` or let DubboBootstrap/FrameworkModel.defaultModel() lazily create a fresh one (destroy resets the global default).
- In tests, ensure each test creates its own FrameworkModel/ApplicationModel and destroys it fully in teardown, or call FrameworkModel.destroyAll() to clear the global registry before the next test.
- If using DubboBootstrap, start a new DubboBootstrap instance rather than calling methods on the one you destroyed.
- Guard access with `if (!frameworkModel.isDestroyed())` before calling defaultApplication()/addApplication().
Example fix
// before FrameworkModel fm = FrameworkModel.defaultModel(); fm.destroy(); ApplicationModel app = fm.defaultApplication(); // throws // after FrameworkModel fm = FrameworkModel.defaultModel(); fm.destroy(); // destroyed model resets the global default; a new one is created lazily ApplicationModel app = FrameworkModel.defaultModel().defaultApplication();
Defensive patterns
Strategy: validation
Validate before calling
if (frameworkModel == null || frameworkModel.isDestroyed()) {
frameworkModel = FrameworkModel.defaultModel(); // get/create a live model
}
ApplicationModel app = frameworkModel.defaultApplication(); Prevention
- Treat FrameworkModel as single-use: never call mutating APIs after destroy().
- In tests, destroy models in @AfterEach and let the next test obtain a fresh FrameworkModel.defaultModel().
- Do not cache a FrameworkModel field across destroy/restart boundaries; re-resolve it.
- Use DubboBootstrap to manage lifecycle rather than destroying models by hand.
When it happens
Trigger: Calling frameworkModel.defaultApplication() or frameworkModel.addApplication(...) after frameworkModel.destroy() has run. Also occurs when ApplicationModel.of(frameworkModel) is constructed against a destroyed framework, or when a background destroy thread races a re-initialization thread in test harnesses that reuse the same FrameworkModel.
Common situations: Unit/integration tests that call FrameworkModel.defaultModel().destroy() (or DubboBootstrap.getInstance().destroy()) in @AfterEach and then start a new DubboBootstrap in the next test without resetting the global default. Long-running apps that intentionally destroy and re-create the framework. Spring context refresh/destroy cycles where the FrameworkModel bean is scoped incorrectly (singleton reused across restarts).
Related errors
- Directory of type {simpleName} already destroyed for service
- Rpc cluster invoker for {getInterface()} on consumer {NetUti
- register bean failed! name=${name}, type=${className}
- ScopeBeanFactory is destroyed
- ExtensionDirector is destroyed
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/5b8d91a9ea27ce62.
Report an issue: GitHub.