Skip to content

fix(tools): prevent duplicate tool invocation on failure (#7449) - #7452

Open
VimalN2005 wants to merge 2 commits into
crewAIInc:mainfrom
VimalN2005:fix/tool-usage-retry-double-invoke
Open

VimalN2005 wants to merge 2 commits into
crewAIInc:mainfrom
VimalN2005:fix/tool-usage-retry-double-invoke

Conversation

@VimalN2005

Copy link
Copy Markdown

Related issue

Fixes #7449

Summary

In ToolUsage._use and _ause, tool.invoke(...) and tool.ainvoke(...) were executed inside the inner try...except block intended solely for filtering calling.arguments against tool.args_schema.

When a tool raised a runtime exception during invocation, the inner except Exception: caught it and re-invoked tool.invoke() a second time with unfiltered arguments within the same outer attempt. This caused every failure to invoke the tool twice per attempt (up to 6 times under default _max_parsing_attempts=3).

Solution

  • Moved tool.invoke() and await tool.ainvoke() outside the inner arguments schema filtering try...except block in both _use and _ause.
  • Arguments schema filtering remains safely guarded by the try...except fallback to calling.arguments.
  • Added unit tests covering both sync and async execution paths to guarantee single invocation per attempt on failure.

Verification

  • Tests added or updated for the changed behavior

  • Relevant tests and quality checks pass locally

  • Added test_tool_usage_does_not_double_invoke_on_failure and test_async_tool_usage_does_not_double_invoke_on_failure in lib/crewai/tests/tools/test_tool_usage.py.

  • Ran pytest lib/crewai/tests/tools/test_tool_usage.py (30 passed).

  • Verified mypy type check passes on lib/crewai/src/crewai/tools/tool_usage.py.

  • Formatted with ruff.

Additional context

This PR was authored with AI assistance and should receive the llm-generated label per CONTRIBUTING.md.

)

Move tool invocation outside inner schema-filtering try-except block in _use and _ause so that failing tool calls are not invoked twice per attempt in ToolUsage.
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 4f37d4f3-b947-4460-8af2-645bb44d4180

📥 Commits

Reviewing files that changed from the base of the PR and between 9ad41b8 and ad595b9.

📒 Files selected for processing (1)
  • lib/crewai/tests/tools/test_tool_usage.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/tests/tools/test_tool_usage.py

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The synchronous and asynchronous tool usage paths now catch errors only while filtering arguments. Tool invocation failures propagate to the existing outer retry handling. New tests verify two invocations when the maximum attempts value is two.

Changes

Tool invocation retry handling

Layer / File(s) Summary
Invocation error scope
lib/crewai/src/crewai/tools/tool_usage.py
The synchronous and asynchronous paths keep only argument construction inside the fallback handler. Tool invocation errors now propagate to the outer error-handling and retry path.
Retry regression tests
lib/crewai/tests/tools/test_tool_usage.py
New synchronous and asynchronous tests verify that a failing tool is invoked exactly twice when _max_parsing_attempts is set to two.

Sequence Diagram(s)

sequenceDiagram
  participant ToolUsage
  participant CrewStructuredTool
  participant OuterRetryLogic
  ToolUsage->>CrewStructuredTool: invoke or ainvoke
  CrewStructuredTool-->>OuterRetryLogic: invocation failure
  OuterRetryLogic->>CrewStructuredTool: retry on next configured attempt
Loading

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to ad595

The retry behavior now limits failing tools to one invocation per configured attempt in both execution modes, preventing the duplicate side effects addressed by this change.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: preventing duplicate tool invocation when a tool fails.
Description check ✅ Passed The description includes the related issue, a clear summary of the cause and solution, verification details, updated tests, and additional context.
Linked Issues check ✅ Passed Issue #7449 requires at most one tool invocation per outer attempt in synchronous and asynchronous execution. In ToolUsage._use and _ause, tool.invoke and tool.ainvoke now execute after the fi…
Out of Scope Changes check ✅ Passed The changes modify only the two ToolUsage invocation paths and add focused synchronous and asynchronous regression tests for issue #7449. The changes have a direct connection to the linked issue. No…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ToolUsage retries a failed tool call twice per outer attempt, not once (schema-args-filter fallback in _use/_ause)

1 participant