egametang/ET · error · RpcException
Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: actorId:
Error message
Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: actorId: {actorId} {request}, response: {response} What it means
An Actor RPC returned ErrorCode.ERR_MessageTimeout — the request was sent but no reply arrived within the timeout window. The message explicitly warns about deadlocks or missing reply handlers, the two dominant root causes in the ET actor model. It is thrown as RpcException only when the response error code equals ERR_MessageTimeout.
Source
Thrown at Packages/cn.etetet.netinner/Scripts/Hotfix/Server/MessageSenderSystem.cs:68
{
response = await self.ProcessInnerSender.Call(actorId.FiberInstanceId, request, timeout, needException);
}
else
{
// 发给NetInner纤程
A2NetInner_Request a2NetInner_Request = A2NetInner_Request.Create();
a2NetInner_Request.ActorId = actorId;
a2NetInner_Request.MessageObject = request;
FiberInstanceId netInnerFiberInstanceId = self.GetSingleton<ProcessFiberAddressSingleton>().Get(SceneType.NetInner);
using A2NetInner_Response a2NetInnerResponse = await self.ProcessInnerSender.Call(
netInnerFiberInstanceId, a2NetInner_Request, timeout) as A2NetInner_Response;
response = a2NetInnerResponse.MessageObject;
}
if (response.Error == ErrorCode.ERR_MessageTimeout)
{
throw new RpcException(response.Error, $"Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: actorId: {actorId} {request}, response: {response}");
}
if (needException && ErrorCode.IsRpcNeedThrowException(response.Error))
{
throw new RpcException(response.Error, $"Rpc error: actorId: {actorId} {request}, response: {response}");
}
return response;
}
}
}
View on GitHub (pinned to 5cab01f7a8)
Solutions
- Search the request's handler for a missing Reply/response send — every IRequest handler must return/send an IResponse.
- Look for synchronous Call chains that form a cycle across fibers (A calls B, B calls A) and break them with fire-and-forget Send or by reordering.
- Increase the timeout argument if the operation is legitimately long, or move heavy work off the actor fiber.
- Check that the target process and its NetInner fiber are alive and not CPU-starved (logs, profiler).
Example fix
// before — handler does work but never replies
[FriendClass(typeof(SomeComponent))]
public class SomeHandler : MessageHandler<SomeRequest>
{
protected override async ETTask Run(Scene scene, SomeRequest request)
{
await DoWork();
// forgot to reply
}
}
// after — always reply
protected override async ETTask Run(Scene scene, SomeRequest request)
{
await DoWork();
scene.Fiber().Send(request.ActorId, new SomeResponse { ActorId = request.ActorId });
} Defensive patterns
Strategy: try-catch
Try / catch
try { var resp = await sender.Call(actorId, request); }
catch (RpcException ex) when (ex.Error == ErrorCode.ERR_MessageTimeout)
{ Log.Error($"RPC timeout to {actorId}, possible deadlock: {ex}"); /* retry or fail fast */ } Prevention
- Audit every IRequest handler to ensure it always sends a response.
- Avoid synchronous Call cycles across fibers; use Send to break cycles.
- Profile NetInner fiber Update loops for starvation from long handlers.
When it happens
Trigger: The handler fiber never calls reply/response on the request; the handler is blocked on a lock or on another synchronous RPC that waits on this fiber (deadlock); the target process crashed or its NetInner fiber is overloaded; the timeout value passed to Call is too short for the workload.
Common situations: Two fibers mutually calling each other synchronously (Call) and blocking on both; a request handler that does async work but forgets to send the response; a NetInner fiber whose Update loop is starved by a long-running handler; network latency or packet loss on KCP/TCP inner channels exceeding TIMEOUT_TIME.
Related errors
- Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: {request
- actor id is 0: {request}
- Rpc error: actorId: {actorId} {request}, response: {response
- actor id is 0: {message}
- actor id is 0: {iRequest}
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/d38343b8fca39b5c.
Report an issue: GitHub.