apache/dubbo · error · IllegalStateException

ScopeBeanFactory is destroyed

Error message

ScopeBeanFactory is destroyed

What it means

Thrown by ScopeBeanFactory.checkDestroyed whenever any mutating operation (registerBean, createAndRegisterBean, etc.) is attempted after destroy() has flipped the destroyed flag. Once a scope is destroyed its maps are cleared and further registration is illegal; Dubbo fails fast rather than registering into a dead scope.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java:387

                                "An error occurred when destroy bean [name=" + beanInfo.name + ", bean="
                                        + beanInfo.instance + "]: " + e,
                                e);
                    }
                }
            }
            registeredBeanInfos.clear();
            registeredBeanDefinitions.clear();
            beanCache.clear();
        }
    }

    public boolean isDestroyed() {
        return destroyed.get();
    }

    private void checkDestroyed() {
        if (destroyed.get()) {
            throw new IllegalStateException("ScopeBeanFactory is destroyed");
        }
    }

    static final class BeanInfo {
        private final String name;
        private final Object instance;

        BeanInfo(String name, Object instance) {
            this.name = name;
            this.instance = instance;
        }
    }

    static final class BeanDefinition<T> {

        private final String name;
        private final Class<T> beanClass;
        private final Supplier<T> beanFactory;

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Guard every registration with if (!factory.isDestroyed()) { ... } when registration can race with shutdown.
  2. Ensure the ScopeModel/ApplicationModel is still alive before performing registration (check isDestroyed()).
  3. Cancel/await async tasks that may register beans before destroying the model, or destroy after they complete.
  4. In tests, do not reuse a destroyed model; create a fresh ApplicationModel for each test.

Example fix

// before
applicationModel.destroy();
factory.registerBean("late", LateBean.class);  // throws
// after
if (!factory.isDestroyed()) {
    factory.registerBean("late", LateBean.class);
} else {
    log.warn("Skipped late registration: scope already destroyed");
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard registration against a destroyed scope
boolean safeRegister(ScopeBeanFactory f, String name, Class<?> type) {
    if (f.isDestroyed()) {
        log.warn("ScopeBeanFactory destroyed; skipping registration of {}", name);
        return false;
    }
    f.registerBean(name, type);
    return true;
}

Try / catch

try {
    f.registerBean(name, type);
} catch (IllegalStateException e) {
    if ("ScopeBeanFactory is destroyed".equals(e.getMessage())) {
        // scope already torn down; skip or re-queue the registration
    } else throw e;
}

Prevention

When it happens

Trigger: Calling registerBean / registerBeanFactory / registerBeanDefinition / getOrRegisterBean after ScopeBeanFactory.destroy() has run (typically during ApplicationModel/FrameworkModel shutdown). Also when a shutdown hook or scope-destroy races with late bean registration.

Common situations: Trying to register a bean during or after application shutdown; reusing a ScopeModel that was already destroyed; a delayed/async component attempting registration after context close; tests that tear down the model and then touch the factory.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/85dae8947a878577. Report an issue: GitHub.