AmbiguousBehaviorError¶
A short behavior name (researcher) resolves to behaviors in more
than one loaded pack. The runtime can't pick one without an explicit
choice, so it refuses the lookup and asks for the canonical
pack-prefixed form.
This page is the anchor for the framework's canonical-strict /
lookup-lenient name resolution rule. The other lookup errors
(behavior-not-found,
tool-not-found,
ambiguous-tool) link here for the rule
statement.
Quick fix¶
Use the canonical form <pack_name>.<behavior_name>:
# Instead of:
b = rt.get_behavior("researcher") # ambiguous if two packs declare it
# Use the canonical form:
b = rt.get_behavior("diligence.researcher")
The error message names which packs collided and shows the canonical form using one of them as a copy-paste example. The fix is one edit at the call site.
The resolution rule (canonical strict, lookup lenient)¶
The framework resolves behavior names against the runtime registry using two precedence rules, locked in CONTRACT v0.9 #8:
-
Canonical names are strict. A name containing a dot (
diligence.researcher) addresses exactly one symbol — the behavior declared under that fully-qualified name in the loaded packdiligence. If no such symbol exists, the lookup raisesbehavior-not-found. -
Short names are lenient. A name without a dot (
researcher) resolves to a canonical name only when the resolution is unambiguous. If one pack declaresdiligence.researcherand nothing else uses the short nameresearcher, the lookup succeeds. If two packs both declare aresearcher, the lookup refuses withAmbiguousBehaviorError.
The rule keeps the convenient single-pack case ergonomic while making the multi-pack case explicit. Behaviors registered globally (not from a pack) follow the same rule using their declared name as both canonical and short.
The same rule applies to tool name resolution — see
ambiguous-tool.
How to diagnose¶
The error message names every pack that collided on the short name:
AmbiguousBehaviorError: behavior name 'researcher' is ambiguous
across loaded packs
What failed:
The short behavior name 'researcher' resolves to behaviors in
more than one loaded pack: 'diligence', 'research'.
From code:
try:
b = rt.get_behavior("researcher")
except AmbiguousBehaviorError as e:
print(e.name) # 'researcher'
print(e.packs) # ('diligence', 'research')
To see all canonical behavior names the runtime knows about:
When does this fire¶
At rt.get_behavior(name) and equivalent lookups (e.g., the
runtime's internal _lookup_behavior_by_name paths). It does NOT
fire during trigger dispatch — when an event fires and matches both
packs' behaviors, the framework registers them separately and both
fire on a matching event. The error is for explicit by-name access,
not for trigger dispatch.
Why the framework refuses to continue¶
Picking one pack silently would route dispatch by load order, which would change behavior on a re-arrangement of imports. Picking neither would be a no-op that the caller couldn't distinguish from "no behavior matched at all." The runtime refuses the lookup and asks for the canonical name — explicit beats either silent failure.
See failure-model for the
broader principle.
What's related¶
behavior-not-found-error— the sibling for "no behavior under any name." Uses the same resolution rule defined on this page.ambiguous-tool-error— the symmetric case for tool names. Same rule, same recovery.pack-conflict-error— fires at load time when two packs declare the same canonical name. This page is the load-time companion to that.