apache/dubbo · error · RpcException
Directory of type {simpleName} already destroyed for service
Error message
Directory of type {simpleName} already destroyed for service {serviceKey} from registry {url} What it means
Thrown by AbstractDirectory.list() when the directory's 'destroyed' flag is true. Once a Directory is destroyed (consumer unsubscribed, ReferenceConfig destroyed, or module shutting down), it refuses to list invokers and throws RpcException. The directory is the consumer-side registry of providers for a service reference.
Source
Thrown at dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java:206
}
this.consumerUrl = consumerUrlFrom.addParameters(queryMap);
}
this.connectivityExecutor = applicationModel
.getFrameworkModel()
.getBeanFactory()
.getBean(FrameworkExecutorRepository.class)
.getConnectivityScheduledExecutor();
Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
setRouterChain(routerChain);
}
@Override
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (destroyed) {
throw new RpcException(
"Directory of type " + this.getClass().getSimpleName() + " already destroyed for service "
+ getConsumerUrl().getServiceKey() + " from registry " + getUrl());
}
BitList<Invoker<T>> availableInvokers;
SingleRouterChain<T> singleChain = null;
try {
if (routerChain != null) {
routerChain.getLock().readLock().lock();
}
boolean lockAcquired = false;
try {
if (!invokerRefreshReadLock.tryLock(LockUtils.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) {
throw new RpcException(
"Failed to acquire read lock on invokerRefreshLock within timeout. " + "Timeout: "
+ LockUtils.DEFAULT_TIMEOUT + "ms, " + "Lock state: [readLockHeld="
+ invokerRefreshLock.getReadLockCount() + ", writeLockHeld="
+ invokerRefreshLock.isWriteLocked() + ", writeLockHeldByCurrentThread="View on GitHub (pinned to 3a3043227f)
Solutions
- Stop submitting new RPC calls before destroying the reference/container; drain in-flight calls first.
- Check ReferenceConfigCache / the reference's availability (or the ClusterInvoker.isDestroyed()) before invoking in late lifecycle phases.
- Fix shutdown ordering so application business executors are halted before the Dubbo module/reference is destroyed.
Example fix
// before: invoking after shutdown
referenceConfig.destroy();
service.foo(); // throws
// after: guard or order shutdown
if (!clusterInvoker.isDestroyed()) {
service.foo();
}
// destroy only after all callers are quiesced Defensive patterns
Strategy: validation
Validate before calling
// Check directory liveness before issuing an RPC
Directory<T> dir = clusterInvoker.getDirectory();
if (dir.isDestroyed()) {
// skip / fast-fail gracefully instead of triggering the RpcException
return null;
}
return clusterInvoker.invoke(invocation); Try / catch
try {
service.foo();
} catch (RpcException e) {
if (e.getMessage().contains("already destroyed")) {
// consumer is shutting down; do not retry, log and degrade
log.warn("Reference destroyed; skipping call");
return fallback();
}
throw e;
} Prevention
- Drain in-flight RPCs before destroying references / shutting down.
- Check Directory.isDestroyed() (or ClusterInvoker.isDestroyed()) in late lifecycle code.
- Order application shutdown so business executors stop before Dubbo tears down.
When it happens
Trigger: Calling a service (RpcInvocation) through a Dubbo reference whose underlying Directory has been destroyed — i.e., after ReferenceConfig.destroy(), after the Spring container closes, or after dubbo-bootstrap.stop().
Common situations: Application shutdown ordering: business threads still invoking after the Dubbo context is torn down; cached service proxies used after @DubboReference bean was destroyed; a hot-redeploy that destroys the old reference while in-flight calls continue.
Related errors
- Rpc cluster invoker for {getInterface()} on consumer {NetUti
- Failed to acquire read lock on invokerRefreshLock within tim
- Interrupted while acquiring read lock for invoker access, ca
- 6
- Consumer is not initialized
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/5dfd63f018df54c5.
Report an issue: GitHub.