egametang/ET · error · Exception

message is null

Error message

message is null

What it means

ProcessOuterSender.SendInner requires a non-null MessageObject. The public Send method casts the IMessage to MessageObject, and if that cast yields null (e.g. the IMessage is not a MessageObject subclass) the guard throws. This prevents sending an empty buffer over the outer channel.

Source

Thrown at Packages/cn.etetet.netinner/Scripts/Hotfix/Server/ProcessOuterSenderSystem.cs:199

            self.SetResult(response);
        }

        public static void Send(this ProcessOuterSender self, ActorId actorId, IMessage message)
        {
            self.SendInner(actorId, message as MessageObject);
        }

        private static void SendInner(this ProcessOuterSender self, ActorId actorId, MessageObject message)
        {
            if (actorId == default)
            {
                throw new Exception($"actor id is 0: {message}");
            }
            
            if (message == null)
            {
                throw new Exception($"message is null");
            }

            // 如果发向同一个进程,则报错
            if (actorId.Address == self.GetSingleton<AddressSingleton>().InnerAddress)
            {
                throw new Exception($"actor is the same process: {actorId}");
            }
            Session session = self.Get(actorId.Address);
            session.Send(actorId.FiberInstanceId, message);
        }

        private static int GetRpcId(this ProcessOuterSender self)
        {
            return ++self.RpcId;
        }

        public static async ETTask<IResponse> Call(this ProcessOuterSender self, ActorId actorId, IRequest iRequest, bool needException = true)
        {

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Ensure the message type extends MessageObject / is a proper ET message (generated via the schema).
  2. Add a null check before calling Send so the error is logged with context rather than thrown deep in the sender.
  3. Verify the message was created via the framework's Create() factory rather than new'd directly.

Example fix

// before
outerSender.Send(actorId, msg as IMessage);

// after
if (msg is not MessageObject mo)
{
    Log.Error($"message is null or not a MessageObject: {msg}");
    return;
}
outerSender.Send(actorId, mo);
Defensive patterns

Strategy: type-guard

Validate before calling

if (message is not MessageObject) { Log.Error($"message is null or not a MessageObject: {message}"); return; }

Type guard

static bool IsValidMessage(IMessage msg) => msg is MessageObject;

Prevention

When it happens

Trigger: Passing a message object that does not inherit from MessageObject (so the `as` cast returns null); passing a literally null IMessage reference to Send.

Common situations: A message type was defined without the required MessageObject base class; a hand-constructed IMessage implementation that is not part of the ET message hierarchy; a code path that passes null because a Create() call failed or was skipped.

Related errors


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