fix(flow): explain the route-label/method-name collision in the self-listen error (#6767) - #6777
Open
Anai-Guo wants to merge 1 commit into
Open
Conversation
…listen error (crewAIInc#6767) `FlowDefinition._validate_trigger_namespace` rejects a method whose @listen condition names the method itself. In a conversational flow the string passed to @listen is a router route label, so naming the handler after the route it serves -- the most natural naming there is -- trips the guard and surfaces as "methods.create_video.listen must not reference itself", which reads as if the developer wrote a self-referential method trigger they never wrote. The guard itself is correct and has to stay: route labels and method names share one trigger namespace, and the runtime re-triggers listeners on the completing method's own name, so allowing the collision would make the handler re-trigger itself until `max_method_calls` raises RecursionError (whose message already blames "a @listen label matches the method's own name"). So keep rejecting it, but say why. The error now names the collision for conversational flows and points at the fix (rename the handler, keep the @listen label), and explains the re-trigger reasoning for regular flows.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe flow validator now adds contextual explanations to self-reference errors. Standard flows report repeated-trigger risk. Conversational flows identify route-label and method-name collisions. Tests cover both validation messages. ChangesSelf-reference validation
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6767.
What's going on
In a conversational
Flow, the string passed to@listen("...")is a router route label.FlowDefinition._validate_trigger_namespacealso uses that field for method-to-method triggers, so naming a handler after the route it serves — the naming everyone reaches for first — fails at instantiation with:which sends you looking for a self-referential trigger you never wrote.
Why the guard has to stay
The issue offered two options; I went with the second (explain the collision) because separating the namespaces would reintroduce the infinite loop the guard exists to prevent.
Route labels and method names are genuinely one trigger namespace at runtime. After a listener runs,
_execute_single_listenercalls_execute_listeners(listener_name, ...)(flow/runtime/__init__.py), so a method that listens for its own name re-triggers itself on every completion. The engine already knows this — themax_method_callsRecursionErrorsays "This commonly happens when a @listen label matches the method's own name." Allowing@listen("create_video")ondef create_videowould just trade an instantiation-time error for a runtime loop that burnsmax_method_callsLLM turns first.The change
Keep rejecting it, but say why, and tailor the explanation to the flow kind:
Conversational flow (new):
Regular flow (new):
Validation behaviour is unchanged — same flows are accepted and rejected, only the message text is new.
Verification
Reproduced the issue's snippet verbatim against
crewai1.15.9, whoseflow_definition.py,conversational_definition.pyandflow/dsl/_utils.pyare byte-identical tomain, then re-ran it with the patch applied.lib/crewai/tests/test_flow_definition.py(one per branch). Both fail onmainand pass with the fix.test_flow_definition.py: 61 passed.ruff==0.15.1 format --config pyproject.toml: already formatted.ruff checkreports one pre-existingI001on this file that is present onmainunchanged, so I left the import block alone rather than churning it into the diff.🤖 Generated with Claude Code