Skip to content

fix(tools): raise ToolUsageError instead of bare raise in _original_tool_calling#6448

Open
C0d3N1nja97342 wants to merge 2 commits into
crewAIInc:mainfrom
C0d3N1nja97342:fix/original-tool-calling-bare-raise
Open

fix(tools): raise ToolUsageError instead of bare raise in _original_tool_calling#6448
C0d3N1nja97342 wants to merge 2 commits into
crewAIInc:mainfrom
C0d3N1nja97342:fix/original-tool-calling-bare-raise

Conversation

@C0d3N1nja97342

Copy link
Copy Markdown

Problem

ToolUsage._original_tool_calling (lib/crewai/src/crewai/tools/tool_usage.py) executed a bare raise outside any except block when _validate_tool_input returned a non-dict and raise_error=True. Because no exception was active on that path (the preceding try/except had completed normally), Python raised RuntimeError: No active exception to re-raise instead of a meaningful error. This produced a confusing error message and caused the caller _tool_calling to log/retry against a RuntimeError rather than a descriptive ToolUsageError.

Reported in #6430.

Solution

Construct a ToolUsageError once and raise it when raise_error=True (or return it when raise_error=False), mirroring the existing raise_error=False return path. The sole caller _tool_calling still catches it via except Exception and falls back to _function_calling / retry exactly as before, so behavior is backward compatible — the only difference is that the exception now carries a meaningful message instead of RuntimeError.

No signature, return-type annotation, or public API change. Minimal and scoped to the bug.

Changes

  • lib/crewai/src/crewai/tools/tool_usage.py — in _original_tool_calling, replaced the bare raise in the non-dict branch with raise tool_arguments_error (a constructed ToolUsageError); the raise_error=False path returns the same object.
  • lib/crewai/tests/tools/test_tool_usage.py — added ToolUsageError import, a small ToolUsage builder helper, and 3 tests covering:
    • happy path (valid dict → ToolCalling)
    • non-dict + raise_error=True → raises ToolUsageError (regression: was RuntimeError)
    • non-dict + raise_error=False → returns ToolUsageError (compatibility)

Testing

  • New unit tests pass: uv run pytest lib/crewai/tests/tools/test_tool_usage.py -k original_tool_calling3 passed.
  • A minimal runtime demo verified all three paths (happy / raise / return).
  • ruff check and ruff format --check are clean on the changed files.
  • Note: 5 pre-existing event-bus tests in test_tool_usage.py fail locally on a clean main checkout (confirmed via git stash + re-run) — they are environment/flaky (threading + event bus on Windows) and unrelated to this change.

Notes for Reviewer

  • This is an AI-assisted contribution. Per .github/CONTRIBUTING.md, the llm-generated label is required — I've attempted to apply it; if the tooling does not permit external contributors to label PRs, please add it.
  • Fixes [BUG] Bare raise in ToolUsage._original_tool_calling causes RuntimeError instead of ToolUsageError #6430.
  • Design choice: I kept the defensive if not isinstance(arguments, dict) branch rather than removing it. Since _validate_tool_input currently guarantees dict-or-raise, the branch is effectively defensive/dead, but I chose the minimal fix (correct the raise) over removing the branch to keep the change scoped to the bug. Happy to remove the branch instead if preferred.

…ool_calling

ToolUsage._original_tool_calling executed a bare `raise` outside any except block when _validate_tool_input returned a non-dict and raise_error=True. With no active exception this raised `RuntimeError: No active exception to re-raise` instead of a meaningful error. Raise a constructed ToolUsageError, consistent with the raise_error=False return path. The sole caller (_tool_calling) still catches it via `except Exception` and falls back to function-calling, so behavior is backward compatible.
Add regression tests for _original_tool_calling: happy path returns ToolCalling; non-dict with raise_error=True raises ToolUsageError (not RuntimeError); non-dict with raise_error=False returns ToolUsageError. Mirrors the patch.object style of test_tool_validate_input_error_event.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 694a22a0-a2e4-43a8-a423-10869a0d40b1

📥 Commits

Reviewing files that changed from the base of the PR and between 2b90117 and f4c3aec.

📒 Files selected for processing (2)
  • lib/crewai/src/crewai/tools/tool_usage.py
  • lib/crewai/tests/tools/test_tool_usage.py

📝 Walkthrough

Walkthrough

The PR fixes a bare raise statement in ToolUsage._original_tool_calling that caused a RuntimeError instead of a meaningful ToolUsageError when tool arguments were not a dict. It also adds regression tests covering both raise_error=True and raise_error=False paths.

Changes

Bare Raise Fix and Regression Tests

Layer / File(s) Summary
Explicit error raising
lib/crewai/src/crewai/tools/tool_usage.py
Constructs a named ToolUsageError instance for non-dict arguments and raises that same instance when raise_error=True, or returns it when raise_error=False, replacing the previous bare raise.
Regression tests
lib/crewai/tests/tools/test_tool_usage.py
Imports ToolUsageError, adds a helper _build_tool_usage_for_original_calling, and adds tests verifying valid dict input yields ToolCalling and non-dict input yields ToolUsageError via raise or return.

Related Issues: #6430

Suggested Labels: bug, tests

Suggested Reviewers: None specifically identified

Poem

A bare raise lurked with no exception near,
Now a ToolUsageError makes the failure clear.
Tests stand watch, both raise and return,
No more RuntimeError for us to discern.
A rabbit hops on, code fixed and bright. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the core fix in _original_tool_calling and matches the changeset.
Description check ✅ Passed The description accurately describes the bug, fix, and added tests in the PR.
Linked Issues check ✅ Passed The change raises ToolUsageError on the non-dict path, preserves the false branch, and adds regression tests as requested in #6430.
Out of Scope Changes check ✅ Passed The diff stays scoped to tool_usage.py and its tests, with no unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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.

[BUG] Bare raise in ToolUsage._original_tool_calling causes RuntimeError instead of ToolUsageError

1 participant