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

  1. Search the request's handler for a missing Reply/response send — every IRequest handler must return/send an IResponse.
  2. 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.
  3. Increase the timeout argument if the operation is legitimately long, or move heavy work off the actor fiber.
  4. 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

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


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/d38343b8fca39b5c. Report an issue: GitHub.