egametang/ET · error · Exception
actor id is 0: {iRequest}
Error message
actor id is 0: {iRequest} What it means
ProcessOuterSender.Call (the RPC variant) rejects a default/zero ActorId before setting up the rpcId callback and sending. Same precondition as the Send path but on the request/response flow — a zero id means there is no remote process to receive the RPC.
Source
Thrown at Packages/cn.etetet.netinner/Scripts/Hotfix/Server/ProcessOuterSenderSystem.cs:220
// 如果发向同一个进程,则报错
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)
{
if (actorId == default)
{
throw new Exception($"actor id is 0: {iRequest}");
}
Fiber fiber = self.Fiber();
int rpcId = self.GetRpcId();
iRequest.RpcId = rpcId;
Type requestType = iRequest.GetType();
MessageSenderStruct messageSenderStruct = new(actorId, requestType, needException);
self.requestCallback.Add(rpcId, messageSenderStruct);
self.SendInner(actorId, iRequest as MessageObject);
EntityRef<ProcessOuterSender> selfRef = self;
async ETTask Timeout()
{
await fiber.Root.TimerComponent.WaitAsync(ProcessOuterSender.TIMEOUT_TIME);
self = selfRef;
if (!self.requestCallback.Remove(rpcId, out MessageSenderStruct action))View on GitHub (pinned to 5cab01f7a8)
Solutions
- Resolve and validate the target ActorId (non-zero, address registered) before calling Call.
- Ensure the destination process is in the start config and its outer address is known.
- Guard with a default check and degrade gracefully (return a failure response) instead of throwing.
Example fix
// before
var resp = await outerSender.Call(actorId, request);
// after
if (actorId == default)
{
return new SomeResponse { Error = ErrorCode.ERR_ActorIdInvalid };
}
var resp = await outerSender.Call(actorId, request); Defensive patterns
Strategy: validation
Validate before calling
if (actorId == default) { return new SomeResponse { Error = ErrorCode.ERR_ActorIdInvalid }; } Prevention
- Guard Call with a default check and return a typed failure response.
- Ensure target process addresses are registered before RPC traffic.
- Log the ActorId source when it is zero to find config gaps.
When it happens
Trigger: Calling ProcessOuterSender.Call(actorId, iRequest) where actorId is default; the address look-up for the target process returned nothing.
Common situations: The target process is not configured or not yet started; a player/entity ActorId was not initialized before an RPC; single-process dev mode calling outer RPC with no remote process configured.
Related errors
- actor id is 0: {request}
- actor id is 0: {message}
- Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: actorId:
- Rpc error: actorId: {actorId} {request}, response: {response
- message is null
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/829ef57d57e1953a.
Report an issue: GitHub.