UAT: ToolCallRouter.route_streaming catches ToolError and Exception together (redundant combined handler) #5469

Open
opened 2026-04-09 06:56:29 +00:00 by HAL9000 · 1 comment
Owner

Bug Report

Feature Area: Tool Router — Streaming execution / Error handling
Severity: Backlog — code quality issue, ToolError loses its structured context in streaming path
Found by: UAT Testing (tool-router-mcp-adapter area)

What Was Tested

Code-level analysis of src/cleveragents/tool/router.py — specifically the route_streaming() method (lines 702–849) and its exception handling.

Expected Behavior (from spec)

ToolError is a structured exception with tool_name, error_type, and details attributes. The router should handle ToolError separately from generic Exception to preserve this structured context in the error result, consistent with how route() handles it.

Actual Behavior

In route_streaming(), both ToolError and generic Exception are caught together in a single handler:

# route_streaming (lines 779-807)
except (ToolError, Exception) as exc:
    elapsed = (time.monotonic() - start) * 1000.0
    error_cat = classify_tool_error(str(exc))
    # ... same handling for both

This is inconsistent with route() which correctly handles them separately:

# route() (lines 593-632)
except ToolError as exc:
    elapsed = (time.monotonic() - start) * 1000.0
    error_cat = classify_tool_error(str(exc))
    # ToolError-specific handling
    ...
except Exception as exc:
    elapsed = (time.monotonic() - start) * 1000.0
    error_cat = classify_tool_error(str(exc))
    # Generic exception handling
    ...

The combined except (ToolError, Exception) in route_streaming is also logically redundant since ToolError is a subclass of ExceptionToolError would be caught by except Exception alone.

Code Location

  • Bug: src/cleveragents/tool/router.py, line 779 — except (ToolError, Exception) as exc:

Impact

  • ToolError's structured attributes (tool_name, error_type, details) are not used in the streaming error path
  • The error message in the streaming result is str(exc) which formats as "[ErrorType] tool_name: details" — the structured fields are lost
  • Inconsistency between route() and route_streaming() makes the API harder to reason about

Fix

Split the exception handler in route_streaming() to match route():

except ToolError as exc:
    elapsed = (time.monotonic() - start) * 1000.0
    error_cat = classify_tool_error(str(exc))
    # ... yield error update and result
except Exception as exc:
    elapsed = (time.monotonic() - start) * 1000.0
    error_cat = classify_tool_error(str(exc))
    # ... yield error update and result

Metadata

Commit Message: fix(tool): split ToolError/Exception handlers in route_streaming for consistency with route()
Branch: fix/tool-router-streaming-error-handling

Subtasks

  • Split except (ToolError, Exception) into separate handlers in route_streaming()
  • Add unit tests for route_streaming() error handling with ToolError vs generic exceptions

Definition of Done

  • route_streaming() handles ToolError and Exception in separate except blocks
  • Error handling is consistent between route() and route_streaming()
  • All existing tests pass

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Bug Report **Feature Area:** Tool Router — Streaming execution / Error handling **Severity:** Backlog — code quality issue, ToolError loses its structured context in streaming path **Found by:** UAT Testing (tool-router-mcp-adapter area) ### What Was Tested Code-level analysis of `src/cleveragents/tool/router.py` — specifically the `route_streaming()` method (lines 702–849) and its exception handling. ### Expected Behavior (from spec) `ToolError` is a structured exception with `tool_name`, `error_type`, and `details` attributes. The router should handle `ToolError` separately from generic `Exception` to preserve this structured context in the error result, consistent with how `route()` handles it. ### Actual Behavior In `route_streaming()`, both `ToolError` and generic `Exception` are caught together in a single handler: ```python # route_streaming (lines 779-807) except (ToolError, Exception) as exc: elapsed = (time.monotonic() - start) * 1000.0 error_cat = classify_tool_error(str(exc)) # ... same handling for both ``` This is inconsistent with `route()` which correctly handles them separately: ```python # route() (lines 593-632) except ToolError as exc: elapsed = (time.monotonic() - start) * 1000.0 error_cat = classify_tool_error(str(exc)) # ToolError-specific handling ... except Exception as exc: elapsed = (time.monotonic() - start) * 1000.0 error_cat = classify_tool_error(str(exc)) # Generic exception handling ... ``` The combined `except (ToolError, Exception)` in `route_streaming` is also logically redundant since `ToolError` is a subclass of `Exception` — `ToolError` would be caught by `except Exception` alone. ### Code Location - **Bug**: `src/cleveragents/tool/router.py`, line 779 — `except (ToolError, Exception) as exc:` ### Impact - `ToolError`'s structured attributes (`tool_name`, `error_type`, `details`) are not used in the streaming error path - The error message in the streaming result is `str(exc)` which formats as `"[ErrorType] tool_name: details"` — the structured fields are lost - Inconsistency between `route()` and `route_streaming()` makes the API harder to reason about ### Fix Split the exception handler in `route_streaming()` to match `route()`: ```python except ToolError as exc: elapsed = (time.monotonic() - start) * 1000.0 error_cat = classify_tool_error(str(exc)) # ... yield error update and result except Exception as exc: elapsed = (time.monotonic() - start) * 1000.0 error_cat = classify_tool_error(str(exc)) # ... yield error update and result ``` ### Metadata ``` Commit Message: fix(tool): split ToolError/Exception handlers in route_streaming for consistency with route() Branch: fix/tool-router-streaming-error-handling ``` ### Subtasks - [ ] Split `except (ToolError, Exception)` into separate handlers in `route_streaming()` - [ ] Add unit tests for `route_streaming()` error handling with `ToolError` vs generic exceptions ### Definition of Done - `route_streaming()` handles `ToolError` and `Exception` in separate `except` blocks - Error handling is consistent between `route()` and `route_streaming()` - All existing tests pass --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.2.0 milestone 2026-04-09 06:59:18 +00:00
Author
Owner

Label compliance fix applied:

  • Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#5469
No description provided.