egametang/ET · error · Exception

not found bt handler: {node.GetType().FullName}

Error message

not found bt handler: {node.GetType().FullName}

What it means

BTDispatcher.Handle looked up node.GetType() in its internal btHandlers dictionary and found no registered IBTHandler for that node type. The dictionary is populated at startup by scanning all [BTHandlerAttribute]-decorated types and keying them by the result of GetNodeType(). If no handler's GetNodeType() returns this node's type, dispatch fails.

Source

Thrown at Packages/cn.etetet.behaviortree/Scripts/Model/Share/BTDispatcher.cs:64

            if (ibtHandler == null)
            {
                throw new Exception($"bt handler not inherit IMActorHandler abstract class: {obj.GetType().FullName}");
            }

            Type nodeType = ibtHandler.GetNodeType();
            this.btHandlers.Add(nodeType, ibtHandler);
        }
        
        
        public int Handle(BTNode node, BTEnv env)
        {
            if (node == null)
            {
                throw new Exception($"bt node is null");
            }
            if (!this.btHandlers.TryGetValue(node.GetType(), out IBTHandler ibtHandler))
            {
                throw new Exception($"not found bt handler: {node.GetType().FullName}");
            }
            int ret = ibtHandler.Handle(node, env);
            
#if UNITY_EDITOR
            env.AddSnapshot($"Node {node.GetType().Name} {node.Id} return {ret}");
#endif
            return ret;
        }
    }
}

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Create a class that implements IBTHandler, decorate it with [BTHandlerAttribute], and have its GetNodeType() return the exact BTNode subtype being dispatched.
  2. Verify GetNodeType() returns the concrete node type (typeof(MyNode)), not a base type.
  3. Ensure the handler class is in an assembly included in the CodeTypes scan (check assembly definitions and [CodeProcess] attributes).
  4. Check that the handler class has [BTHandlerAttribute] — without it, BTDispatcher.Awake won't register it.

Example fix

// before — MyNode has no handler, dispatch throws
BTDispatcher.Instance.Handle(myNode, env);

// after — add a handler for MyNode
[BTHandler]
public class MyNodeHandler: IBTHandler
{
    public Type GetNodeType() => typeof(MyNode);
    public int Handle(BTNode node, BTEnv env)
    {
        var myNode = (MyNode)node;
        // ... execute node logic ...
        return BTResult.Success;
    }
}
Defensive patterns

Strategy: type-guard

Type guard

// Guard before dispatching (requires a public method on BTDispatcher):
// Add to BTDispatcher:
//   public bool HasHandler(BTNode node) => btHandlers.ContainsKey(node.GetType());
//
// Then at the call site:
if (!BTDispatcher.Instance.HasHandler(node))
{
    Log.Error($"No BT handler registered for node type: {node.GetType().FullName}");
    return BTResult.Failure;
}
int ret = BTDispatcher.Instance.Handle(node, env);

Prevention

When it happens

Trigger: Dispatching a BTNode whose concrete runtime type has no corresponding handler. This happens when a new BTNode subclass is added without a matching handler, or when a handler's GetNodeType() returns a different (base) type than the node being dispatched.

Common situations: A new BTNode subtype was created but no [BTHandlerAttribute] handler class was written for it. A handler's GetNodeType() returns typeof(BaseNode) instead of typeof(ConcreteNode). The handler class is missing the [BTHandlerAttribute] decoration so it was never registered. The handler is in an assembly not scanned by CodeTypes.

Related errors


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