retry_auto_debug raises generic Exception instead of preserving error type when result dict contains "error" key #8464

Open
opened 2026-04-13 19:22:41 +00:00 by HAL9000 · 2 comments
Owner

Metadata

  • Commit: Build: Reinforced label enforcement, and ensure implementation workers dont continue work on a mergable PR.
  • Branch: main
  • SHA: 5a9aaa79ed

Background and Context

retry_auto_debug in src/cleveragents/core/retry_service_patterns.py tracks the last error in a variable typed as Exception | str | None. When the decorated function returns a dict with an "error" key (rather than raising an exception), last_error is set to str(error_value) — a plain string. At the end of the retry loop, if all attempts fail via this dict-error path, the code raises Exception(last_error) — a generic Exception wrapping a string.

This loses all error type information: callers cannot distinguish between a NetworkError, ProviderError, or any other domain-specific error type. The error handling hierarchy defined in exceptions.py is bypassed entirely.

Current Behavior

# In retry_service_patterns.py - retry_auto_debug wrapper:
last_error: Exception | str | None = None

# When result is a dict with "error" key:
error_value: Any = result.get("error")
if error_value is not None:
    last_error = str(error_value)   # ← string, loses type info
    ...

# At end of all attempts:
if last_error is not None:
    if isinstance(last_error, Exception):
        raise last_error   # ← correct for exception path
    raise Exception(last_error)   # ← generic Exception for string path, loses type!

Expected Behavior

When the dict-error path is taken, the error should be wrapped in a domain-appropriate exception type rather than a generic Exception. At minimum, it should use CleverAgentsError or ExecutionError from the exception hierarchy:

from cleveragents.core.exceptions import ExecutionError

# At end of all attempts:
if last_error is not None:
    if isinstance(last_error, Exception):
        raise last_error
    raise ExecutionError(str(last_error))   # ← domain-specific exception

This preserves the error handling hierarchy and allows callers to catch specific exception types.

Acceptance Criteria

  • When retry_auto_debug exhausts all attempts via the dict-error path, it raises a CleverAgentsError subclass (not a generic Exception)
  • The error message is preserved
  • Callers can catch the raised exception using the domain exception hierarchy
  • BDD test scenario verifies the exception type on the dict-error exhaustion path

Subtasks

  • Replace raise Exception(last_error) with raise ExecutionError(str(last_error)) (or appropriate subclass)
  • Import the appropriate exception type in retry_service_patterns.py
  • Add BDD test verifying exception type on dict-error exhaustion
  • Verify no existing tests break

Definition of Done

The issue is closed when retry_auto_debug raises a domain-specific exception (not generic Exception) when exhausting retries via the dict-error path, with a passing BDD test, merged to main.


Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor

## Metadata - **Commit**: Build: Reinforced label enforcement, and ensure implementation workers dont continue work on a mergable PR. - **Branch**: main - **SHA**: 5a9aaa79edaefb1a257114f054ea87facb8efe69 ## Background and Context `retry_auto_debug` in `src/cleveragents/core/retry_service_patterns.py` tracks the last error in a variable typed as `Exception | str | None`. When the decorated function returns a dict with an `"error"` key (rather than raising an exception), `last_error` is set to `str(error_value)` — a plain string. At the end of the retry loop, if all attempts fail via this dict-error path, the code raises `Exception(last_error)` — a generic `Exception` wrapping a string. This loses all error type information: callers cannot distinguish between a `NetworkError`, `ProviderError`, or any other domain-specific error type. The error handling hierarchy defined in `exceptions.py` is bypassed entirely. ## Current Behavior ```python # In retry_service_patterns.py - retry_auto_debug wrapper: last_error: Exception | str | None = None # When result is a dict with "error" key: error_value: Any = result.get("error") if error_value is not None: last_error = str(error_value) # ← string, loses type info ... # At end of all attempts: if last_error is not None: if isinstance(last_error, Exception): raise last_error # ← correct for exception path raise Exception(last_error) # ← generic Exception for string path, loses type! ``` ## Expected Behavior When the dict-error path is taken, the error should be wrapped in a domain-appropriate exception type rather than a generic `Exception`. At minimum, it should use `CleverAgentsError` or `ExecutionError` from the exception hierarchy: ```python from cleveragents.core.exceptions import ExecutionError # At end of all attempts: if last_error is not None: if isinstance(last_error, Exception): raise last_error raise ExecutionError(str(last_error)) # ← domain-specific exception ``` This preserves the error handling hierarchy and allows callers to catch specific exception types. ## Acceptance Criteria - [ ] When `retry_auto_debug` exhausts all attempts via the dict-error path, it raises a `CleverAgentsError` subclass (not a generic `Exception`) - [ ] The error message is preserved - [ ] Callers can catch the raised exception using the domain exception hierarchy - [ ] BDD test scenario verifies the exception type on the dict-error exhaustion path ## Subtasks - [ ] Replace `raise Exception(last_error)` with `raise ExecutionError(str(last_error))` (or appropriate subclass) - [ ] Import the appropriate exception type in `retry_service_patterns.py` - [ ] Add BDD test verifying exception type on dict-error exhaustion - [ ] Verify no existing tests break ## Definition of Done The issue is closed when `retry_auto_debug` raises a domain-specific exception (not generic `Exception`) when exhausting retries via the dict-error path, with a passing BDD test, merged to `main`. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor
Author
Owner

[AUTO-WDOG-4] This issue is missing required labels. Please add:

  • State/* (e.g., State/Unverified for new issues)
  • Priority/* (e.g., Priority/Medium)
  • Type/* (e.g., Type/Bug, Type/Epic)
  • MoSCoW/* if applicable

Required labels must be present for proper tracking and prioritization.


Automated by CleverAgents Bot
Supervisor: System Watchdog | Agent: [AUTO-WDOG-4]

[AUTO-WDOG-4] This issue is missing required labels. Please add: - State/* (e.g., State/Unverified for new issues) - Priority/* (e.g., Priority/Medium) - Type/* (e.g., Type/Bug, Type/Epic) - MoSCoW/* if applicable Required labels must be present for proper tracking and prioritization. --- **Automated by CleverAgents Bot** Supervisor: System Watchdog | Agent: [AUTO-WDOG-4]
Author
Owner

Verified — Bug: error type information lost when retry_auto_debug raises generic Exception. MoSCoW: Should-have. Priority: Medium — error type preservation is important for debugging.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — Bug: error type information lost when retry_auto_debug raises generic Exception. MoSCoW: Should-have. Priority: Medium — error type preservation is important for debugging. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
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.

Dependencies

No dependencies set.

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