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
- Ensure the message type extends MessageObject / is a proper ET message (generated via the schema).
- Add a null check before calling Send so the error is logged with context rather than thrown deep in the sender.
- 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
- Ensure all message types derive from MessageObject via the schema generator.
- Create messages through the framework Create() factory.
- Add a null/type check before Send to fail with context.
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
- actor id is 0: {request}
- actor id is 0: {message}
- actor is the same process: {actorId}
- actor id is 0: {iRequest}
- router manager address is empty.
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/186f3ba761134850.
Report an issue: GitHub.