egametang/ET · error · RpcException

ERR_ActorLocationSenderTimeout4

ERR_ActorLocationSenderTimeout4

Error message

{requestType.FullName}

What it means

In CallInner's ERR_NotFoundActor retry path, the code waits with quadratic backoff (WaitAsync(failTimes * failTimes * 10)). After the backoff await, messageLocationSender was re-acquired from EntityRef and found null — the sender was disposed during the backoff wait. The cumulative backoff across retries grew long enough for the sender to time out.

Source

Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/MessageLocationSenderComponentSystem.cs:300

                        {
                            Log.Debug($"actor send message fail, actorid: {messageLocationSender.Id} {requestType.FullName}");
                            
                            // 这里删除actor,后面等待发送的消息会判断InstanceId,InstanceId不一致返回ERR_NotFoundActor
                            self = selfRef;
                            if (self != null)
                            {
                                self.Remove(messageLocationSender.Id);
                            }
                            return response;
                        }

                        // 等待0.5s再发送
                        root = rootRef;
                        await root.TimerComponent.WaitAsync(failTimes * failTimes * 10);
                        messageLocationSender = messageLocationSenderRef;
                        if (messageLocationSender == null)
                        {
                            throw new RpcException(ErrorCode.ERR_ActorLocationSenderTimeout4, $"{requestType.FullName}");
                        }

                        messageLocationSender.ActorId = default;
                        continue;
                    }
                    case ErrorCode.ERR_MessageTimeout:
                    {
                        throw new RpcException(response.Error, $"{requestType.FullName}");
                    }
                }

                if (ErrorCode.IsRpcNeedThrowException(response.Error))
                {
                    throw new RpcException(response.Error, $"Message: {response.Message} Request: {requestType.FullName}");
                }

                return response;
            }

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Catch RpcException with ERR_ActorLocationSenderTimeout4.
  2. Ensure the actor's location is registered before sending to avoid NotFoundActor.
  3. Stabilize actor placement to prevent migration churn.
  4. Investigate why the target actor is unreachable (crashed, wrong scene, not yet started).
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    IResponse resp = await senderOneType.Call(entityId, iLocationRequest);
}
catch (RpcException e) when (e.Error == ErrorCode.ERR_ActorLocationSenderTimeout4)
{
    // Sender disposed during backoff wait — retry
    IResponse resp = await senderOneType.Call(entityId, iLocationRequest);
}

Prevention

When it happens

Trigger: Call(entityId, iLocationRequest) where the target returns ERR_NotFoundActor repeatedly, triggering retry with quadratic backoff, and the sender is disposed during a WaitAsync call.

Common situations: Actor migration in progress causing repeated NotFoundActor. Long NotFoundActor retry chains (up to 10 iterations). Sender times out during cumulative backoff (10+40+90+160+250+... ms).

Related errors


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