apache/dubbo · error · IllegalStateException
ApplicationModel is destroyed
Error message
ApplicationModel is destroyed
What it means
Thrown by ApplicationModel.checkDestroyed when an operation is attempted on an ApplicationModel that has already been destroyed. After destruction the model is unusable; further access (creating modules, registering configs, etc.) is rejected to prevent use-after-shutdown bugs.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java:283
this.pubModuleModels.remove(moduleModel);
if (moduleModel == defaultModule) {
defaultModule = findDefaultModule();
}
}
}
void tryDestroy() {
synchronized (instLock) {
if (this.moduleModels.isEmpty()
|| (this.moduleModels.size() == 1 && this.moduleModels.get(0) == internalModule)) {
destroy();
}
}
}
private void checkDestroyed() {
if (isDestroyed()) {
throw new IllegalStateException("ApplicationModel is destroyed");
}
}
public List<ModuleModel> getModuleModels() {
return Collections.unmodifiableList(moduleModels);
}
public List<ModuleModel> getPubModuleModels() {
return Collections.unmodifiableList(pubModuleModels);
}
public ModuleModel getDefaultModule() {
if (defaultModule == null) {
synchronized (instLock) {
if (defaultModule == null) {
defaultModule = findDefaultModule();
if (defaultModule == null) {
defaultModule = this.newModule();View on GitHub (pinned to 3a3043227f)
Solutions
- Ensure no tasks/threads touch the ApplicationModel after destroy(); order shutdown so Dubbo stops first or wait for in-flight work.
- In tests, create a fresh ApplicationModel per test rather than reusing a destroyed one.
- Release static/long-lived references to the model before destruction.
Example fix
// before applicationModel.destroy(); // ... later, async task still running: moduleModel = applicationModel.getDefaultModule(); // throws // after // await/quiesce async tasks BEFORE destroy, or recreate the model.
Defensive patterns
Strategy: type-guard
Validate before calling
// Guard all post-shutdown access
if (applicationModel.isDestroyed()) {
throw new IllegalStateException(
"ApplicationModel already destroyed; cannot proceed with this operation");
} Type guard
static boolean isUsable(ApplicationModel m) {
return m != null && !m.isDestroyed();
} Try / catch
try {
applicationModel.getDefaultModule();
} catch (IllegalStateException e) {
if ("ApplicationModel is destroyed".equals(e.getMessage())) {
// recreate or obtain a fresh model rather than reuse the destroyed one
applicationModel = ApplicationModel.defaultModel();
} else {
throw e;
}
} Prevention
- Order shutdown so Dubbo teardown happens after all application work completes.
- In tests, create and destroy an ApplicationModel per test; never reuse destroyed models.
- Clear static/long-lived references to a model before destroying it.
- Quiesce async tasks before calling destroy().
When it happens
Trigger: Any guarded operation on ApplicationModel after destroy() has run. Common in test teardown or application shutdown sequences where a background/late task touches the model after it was torn down.
Common situations: Unit/integration tests that destroy the ApplicationModel in @AfterEach but a later step still references it. Hot-reload or redeploy that destroys a model while async export/import tasks are still running. Spring context refresh/close ordering where beans outlive the Dubbo model. Static references to a model held past its lifecycle.
Related errors
- Not all application models are completely destroyed, remaini
- ScopeBeanFactory is destroyed
- ExtensionDirector is destroyed
- ExtensionLoader is destroyed: ${type}
- Executor is shutdown!
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/23bf73243fa58890.
Report an issue: GitHub.