egametang/ET · error · Exception

actor id is 0: {request}

Error message

actor id is 0: {request}

What it means

Thrown by MessageSender.Call when actorId equals default(ActorId), i.e. a zero/uninitialized actor id. The ET framework requires every Actor RPC to target a valid ActorId (process address + fiber instance id); a zero id means no destination was ever resolved. The guard fires before any network or intra-process dispatch, so it is a pure caller-contract violation.

Source

Thrown at Packages/cn.etetet.netinner/Scripts/Hotfix/Server/MessageSenderSystem.cs:45

            a2NetInnerMessage.FromFiber = fiber.Id;
            a2NetInnerMessage.ActorId = actorId;
            a2NetInnerMessage.MessageObject = message;

            FiberInstanceId netInnerFiberInstanceId = self.GetSingleton<ProcessFiberAddressSingleton>().Get(SceneType.NetInner);
            MessageQueue.Instance.Send(fiber, netInnerFiberInstanceId, a2NetInnerMessage);
        }

        public static async ETTask<IResponse> Call(this MessageSender self, ActorId actorId, IRequest request, bool needException = true)
        {
            return await self.Call(actorId, request, ProcessInnerSender.TIMEOUT_TIME, needException);
        }

        public static async ETTask<IResponse> Call(this MessageSender self, ActorId actorId, IRequest request, long timeout,
            bool needException = true)
        {
            if (actorId == default)
            {
                throw new Exception($"actor id is 0: {request}");
            }
            
            IResponse response;
            if (actorId.Address == self.GetSingleton<AddressSingleton>().InnerAddress)
            {
                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;

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Trace the call site: print/log the actorId value and the scene type or entity it was resolved from right before Call.
  2. Verify the target scene/fiber is actually running in this process or on the target process (check ProcessFiberAddressSingleton / address config).
  3. Replace the raw default with an explicit null-check or 'is target scene started?' guard before calling Call.
  4. Ensure server start order registers all SceneType fibers before any RPC depends on them.

Example fix

// before
MessageSender.Instance.Call(actorId, req);

// after
if (actorId == default)
{
    Log.Error($"target ActorId is zero, cannot send {req}");
    return;
}
MessageSender.Instance.Call(actorId, req);
Defensive patterns

Strategy: validation

Validate before calling

if (actorId == default) { Log.Error($"ActorId is zero, aborting Call for {request}"); return; }

Prevention

When it happens

Trigger: Calling MessageSender.Call(actorId, request) where actorId was never assigned (still default), or where a look-up that should have produced an ActorId returned default (e.g. GetSingleton<ProcessFiberAddressSingleton>().Get(...) for a scene type that is not running in this process).

Common situations: A fiber/scene the caller assumes exists has not been started yet; a configuration file lists a scene type that was never spawned; the caller fetched an ActorId from a dictionary that had no entry and silently returned default; timing during server startup before all fibers register their addresses.

Related errors


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