apache/dubbo · error · RpcException
Interrupted while acquiring read lock for invoker access, ca
Error message
Interrupted while acquiring read lock for invoker access, cause: {cause} What it means
Thrown by AbstractDirectory.list() when the thread waiting on invokerRefreshReadLock.tryLock(...) is interrupted (InterruptedException). The interrupt status is re-set (Thread.currentThread().interrupt()) and the call aborts with RpcException. This is the expected outcome when the calling thread is cancelled/interrupted during an RPC.
Source
Thrown at dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java:237
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="
+ invokerRefreshLock.isWriteLockedByCurrentThread() + "], Service: "
+ getConsumerUrl().getServiceKey());
}
lockAcquired = true;
// use clone to avoid being modified at doList().
if (invokersInitialized) {
availableInvokers = validInvokers.clone();
} else {
availableInvokers = invokers.clone();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RpcException(
"Interrupted while acquiring read lock for invoker access, cause: " + e.getMessage(), e);
} finally {
if (lockAcquired) {
invokerRefreshReadLock.unlock();
}
}
if (routerChain != null) {
singleChain = routerChain.getSingleChain(getConsumerUrl(), availableInvokers, invocation);
singleChain.getLock().readLock().lock();
}
List<Invoker<T>> routedResult = doList(singleChain, availableInvokers, invocation);
if (routedResult.isEmpty()) {
// 2-2 - No provider available.
logger.warn(
CLUSTER_NO_VALID_PROVIDER,
"provider server or registry center crashed",View on GitHub (pinned to 3a3043227f)
Solutions
- Treat interruption as cancellation: ensure the caller propagates/cleans interrupt status and the result is discarded (no retry unless intended).
- If spurious, investigate who interrupts the RPC thread (timeout interruParser, executor shutdown) and align timeout settings so the lock wait is not the long pole.
- Reduce directory lock contention (see error 4) so the read lock is acquired without blocking.
Example fix
// handle interrupt-driven cancellation at the caller
try {
result = service.foo();
} catch (RpcException e) {
if (Thread.currentThread().isInterrupted()) {
// request was cancelled; do not retry blindly
throw new CancellationException("rpc cancelled");
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Avoid calling from an interrupted thread; clear/honor interrupt status deliberately
if (Thread.currentThread().isInterrupted()) {
// decide: cancel the call, or clear the flag if interruption is stale
throw new CancellationException("thread already interrupted before rpc");
}
return directory.list(invocation); Try / catch
try {
return directory.list(invocation);
} catch (RpcException e) {
if (Thread.currentThread().isInterrupted()) {
// interruption-driven cancellation: do not retry; propagate as cancellation
throw new CancellationException("rpc interrupted: " + e.getMessage());
}
throw e;
} Prevention
- Do not reuse interrupted threads for RPCs; honor cancellation semantics.
- Align RPC timeouts so the directory lock wait is not the cause of interruption.
- Reduce directory lock contention (see error 4) to avoid blocking waits.
When it happens
Trigger: The RPC-calling thread is interrupted while blocked waiting for the directory read lock — e.g., the RPC timed out at a higher layer and the waiting thread was interrupted, or the application is shutting down and interrupting worker threads.
Common situations: Request timeouts configured shorter than the lock wait; application shutdown interrupting in-flight requests; a servlet/actor framework cancelling the calling thread mid-RPC.
Related errors
- Failed to acquire read lock on invokerRefreshLock within tim
- INTERNAL_ERROR
- Directory of type {simpleName} already destroyed for service
- Arguments' types are different
- Rpc cluster invoker for {getInterface()} on consumer {NetUti
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/cd5788b02892f3aa.
Report an issue: GitHub.