egametang/ET · error · RpcException

ERR_LocationLockNotFound

ERR_LocationLockNotFound

Error message

location unlock not found type: {locationType} key: {key} oldActorId: {oldActorId}

What it means

TargetSelectHandler<Node>.Handle throws when the TargetSelector node passed in is not assignable to the handler's generic Node type. The dispatcher registers handlers keyed by node Type and, on dispatch, walks node.GetType() up through BaseType to find a match, so a correct registration should never deliver a mismatched node to a handler.

Source

Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs:480

        }

        public static async ETTask UnLock(this LocationComponent self, int locationType, long key, ActorId oldActorId, ActorId newActorId,
        long lockToken)
        {
            EntityRef<LocationComponent> selfRef = self;
            using (await self.Root().CoroutineLockComponent.Wait(CoroutineLockType.Location, key))
            {
                self = selfRef;
                if (self == null)
                {
                    return;
                }

                LocationInfo locationInfo = await self.GetOrLoadInfo(key);
                self = selfRef;
                if (self == null || locationInfo == null || !TryGetRouteState(locationInfo, locationType, out LocationTypeState state))
                {
                    throw new RpcException(ErrorCode.ERR_LocationLockNotFound,
                        $"location unlock not found type: {locationType} key: {key} oldActorId: {oldActorId}");
                }

                Dictionary<int, LocationTypeState> snapshot = CreateStatesSnapshot(locationInfo);
                if (self.IsExpiredLock(state))
                {
                    state.LockToken = default;
                    state.LockExpireTime = default;
                    locationInfo.TypeStates[locationType] = state;

                    try
                    {
                        await self.SaveInfoToDB(locationInfo);
                    }
                    catch
                    {
                        self = selfRef;
                        if (self != null)

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Ensure each TargetSelector subtype has exactly one handler whose generic Node type equals (or is a base of) the node type it should receive.
  2. Confirm GetNodeType() returns typeof(Node) and that this matches the key used in Register (handlers.TryAdd(nodeType, ...)).
  3. Check for duplicate or conflicting registrations across the TargetSelector hierarchy in the handlers dictionary.
  4. Add a dedicated handler for the specific node subtype that is currently mismatching.

Example fix

// before
public async ETTask<int> Handle(TargetSelector node, ...)
{
    if (node is not Node c)
    {
        throw new Exception($"type mismatch: {node.GetType().FullName} to {typeof(Node).Name}");
    }
    return await this.Run(c, unit, spellConfig);
}

// after
public async ETTask<int> Handle(TargetSelector node, ...)
{
    if (node is not Node c)
    {
        Log.Error($"node type mismatch: {node.GetType().FullName} expected {typeof(Node).Name}; returning 0");
        return 0;
    }
    return await this.Run(c, unit, spellConfig);
}
Defensive patterns

Strategy: type-guard

Type guard

static bool IsHandlerFor(ITargetSelectHandler handler, TargetSelector node)
{
    return handler.GetNodeType().IsAssignableFrom(node.GetType());
}

Try / catch

try
{
    return await handler.Handle(node, unit, spellConfig);
}
catch (Exception ex) when (ex.Message.Contains("type mismatch"))
{
    Log.Error($"node/handler type mismatch: {node.GetType().FullName} vs {handler.GetNodeType().Name}");
    return 0;
}

Prevention

When it happens

Trigger: A handler's Handle is invoked with a node whose runtime type is not the registered Node type — happens only if the handlers dictionary was populated for the wrong key, GetNodeType() returns a type inconsistent with the generic constraint, or a node subclass has no dedicated handler and the BaseType walk landed on a handler registered for a sibling type.

Common situations: Two handlers registered under keys in the same inheritance chain causing an ambiguous/incorrect lookup; a TargetSelector subclass added without a matching handler; handler generic Node parameter changed during refactor but GetNodeType unchanged.

Related errors


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