BUG-HUNT: [error-handling] execute_plan CLI command catches Exception and prints raw str(e) without wrap_unexpected — unredacted internal error details exposed to users #6645

Open
opened 2026-04-09 22:41:26 +00:00 by HAL9000 · 0 comments
Owner

Bug Report: [error-handling] — execute_plan bare except Exception bypasses redaction

Severity Assessment

  • Impact: Any exception not caught by the specific handlers (PreflightRejection, InvalidPhaseTransitionError, PlanNotReadyError, ValueError, CleverAgentsError) during agents plan execute is printed verbatim as str(e) without going through wrap_unexpected() or redact_value(). This can expose internal paths, model names, API key fragments embedded in error messages, or other sensitive details.
  • Likelihood: Triggers any time an unclassified error occurs during plan execution — e.g. a TypeError from a broken actor, AttributeError from missing configuration, or a RuntimeError from LLM infrastructure.
  • Priority: Medium

Location

  • File: src/cleveragents/cli/commands/plan.py
  • Function: execute_plan (the agents plan execute command)
  • Lines: 2499–2501

Description

The execute_plan command has a handler for five specific exception types, then a bare except Exception as e fallback that prints the raw exception string directly to the console without applying wrap_unexpected(), redact_value(), or any of the structured error formatting:

# src/cleveragents/cli/commands/plan.py, lines 2481-2501
    except PreflightRejection as e:
        console.print(f"[red]Pre-flight check failed:[/red] {e}")
        raise typer.Abort() from e
    except InvalidPhaseTransitionError as e:
        console.print(f"[red]Invalid transition:[/red] {e}")
        raise typer.Abort() from e
    except PlanNotReadyError as e:
        console.print(f"[red]Plan not ready:[/red] {e}")
        raise typer.Abort() from e
    except ValueError as e:
        console.print(f"[red]Execution Error:[/red] {e}")
        raise typer.Abort() from e
    except CleverAgentsError as e:
        console.print(f"[red]Error:[/red] {e.message}")
        raise typer.Abort() from e
    except Exception as e:
        console.print(f"[red]Unexpected error:[/red] {e}")   # ← raw str(e), no redaction
        raise typer.Abort() from e

This is a regression compared to the main() function's global handler (lines 826–835), which correctly wraps with wrap_unexpected() before displaying:

    except Exception as e:
        from cleveragents.core.error_handling import classify_error, wrap_unexpected
        err_console = get_err_console()
        safe = wrap_unexpected(e)
        info = classify_error(safe)
        err_console.print(
            f"[red]Error [{info.code.value}] {info.code.name}:[/red] {info.message}"
        )
        return 1

The same pattern exists in lifecycle_apply_plan (line 2649):

    except Exception as e:
        if isinstance(e, (typer.Abort, typer.Exit)):
            raise
        console.print(f"[red]Unexpected error:[/red] {e}")   # ← same issue
        raise typer.Abort() from e

Note that ValueError at line 2490 is also printed without redaction — an LLM provider error message may contain an API key fragment from its message like "Invalid API key sk-proj-abc123... (key truncated)".

Evidence

# src/cleveragents/cli/commands/plan.py, line 2499-2501
    except Exception as e:
        console.print(f"[red]Unexpected error:[/red] {e}")  # str(e) unredacted
        raise typer.Abort() from e

For a provider configuration error that includes a key hint in the exception message (common in LiteLLM / OpenAI SDKs):

Unexpected error: AuthenticationError: Invalid API key (provided: sk-proj-abc...XXXX)

Expected Behavior

Unhandled exceptions from execute_plan should be wrapped with wrap_unexpected(), which:

  1. Applies redact_value() to strip secret patterns from the message
  2. Returns a safe CleverAgentsError with a user-friendly message
  3. Stores only a truncated, redacted snippet for diagnostics

Actual Behavior

The raw exception message (possibly containing API key fragments, internal file paths, or model names) is printed directly to the console terminal.

Suggested Fix

Replace the bare handler in both execute_plan and lifecycle_apply_plan with the wrap pattern:

    except Exception as e:
        if isinstance(e, (typer.Abort, typer.Exit)):
            raise
        from cleveragents.core.error_handling import classify_error, wrap_unexpected
        safe = wrap_unexpected(e)
        info = classify_error(safe)
        console.print(
            f"[red]Error [{info.code.value}] {info.code.name}:[/red] {info.message}"
        )
        raise typer.Abort() from e

Also apply redact_value() to the ValueError handler at line 2494:

    except ValueError as e:
        from cleveragents.shared.redaction import redact_value
        console.print(f"[red]Execution Error:[/red] {redact_value(str(e))}")

Category

error-handling / security

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: @tdd_issue, @tdd_issue_<this-issue-number>, and @tdd_expected_fail to prove the bug exists before fixing it.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: [error-handling] — `execute_plan` bare `except Exception` bypasses redaction ### Severity Assessment - **Impact**: Any exception not caught by the specific handlers (`PreflightRejection`, `InvalidPhaseTransitionError`, `PlanNotReadyError`, `ValueError`, `CleverAgentsError`) during `agents plan execute` is printed verbatim as `str(e)` without going through `wrap_unexpected()` or `redact_value()`. This can expose internal paths, model names, API key fragments embedded in error messages, or other sensitive details. - **Likelihood**: Triggers any time an unclassified error occurs during plan execution — e.g. a `TypeError` from a broken actor, `AttributeError` from missing configuration, or a `RuntimeError` from LLM infrastructure. - **Priority**: Medium ### Location - **File**: `src/cleveragents/cli/commands/plan.py` - **Function**: `execute_plan` (the `agents plan execute` command) - **Lines**: 2499–2501 ### Description The `execute_plan` command has a handler for five specific exception types, then a bare `except Exception as e` fallback that prints the raw exception string directly to the console without applying `wrap_unexpected()`, `redact_value()`, or any of the structured error formatting: ```python # src/cleveragents/cli/commands/plan.py, lines 2481-2501 except PreflightRejection as e: console.print(f"[red]Pre-flight check failed:[/red] {e}") raise typer.Abort() from e except InvalidPhaseTransitionError as e: console.print(f"[red]Invalid transition:[/red] {e}") raise typer.Abort() from e except PlanNotReadyError as e: console.print(f"[red]Plan not ready:[/red] {e}") raise typer.Abort() from e except ValueError as e: console.print(f"[red]Execution Error:[/red] {e}") raise typer.Abort() from e except CleverAgentsError as e: console.print(f"[red]Error:[/red] {e.message}") raise typer.Abort() from e except Exception as e: console.print(f"[red]Unexpected error:[/red] {e}") # ← raw str(e), no redaction raise typer.Abort() from e ``` This is a regression compared to the `main()` function's global handler (lines 826–835), which correctly wraps with `wrap_unexpected()` before displaying: ```python except Exception as e: from cleveragents.core.error_handling import classify_error, wrap_unexpected err_console = get_err_console() safe = wrap_unexpected(e) info = classify_error(safe) err_console.print( f"[red]Error [{info.code.value}] {info.code.name}:[/red] {info.message}" ) return 1 ``` The same pattern exists in `lifecycle_apply_plan` (line 2649): ```python except Exception as e: if isinstance(e, (typer.Abort, typer.Exit)): raise console.print(f"[red]Unexpected error:[/red] {e}") # ← same issue raise typer.Abort() from e ``` Note that `ValueError` at line 2490 is also printed without redaction — an LLM provider error message may contain an API key fragment from its message like `"Invalid API key sk-proj-abc123... (key truncated)"`. ### Evidence ```python # src/cleveragents/cli/commands/plan.py, line 2499-2501 except Exception as e: console.print(f"[red]Unexpected error:[/red] {e}") # str(e) unredacted raise typer.Abort() from e ``` For a provider configuration error that includes a key hint in the exception message (common in LiteLLM / OpenAI SDKs): ``` Unexpected error: AuthenticationError: Invalid API key (provided: sk-proj-abc...XXXX) ``` ### Expected Behavior Unhandled exceptions from `execute_plan` should be wrapped with `wrap_unexpected()`, which: 1. Applies `redact_value()` to strip secret patterns from the message 2. Returns a safe `CleverAgentsError` with a user-friendly message 3. Stores only a truncated, redacted snippet for diagnostics ### Actual Behavior The raw exception message (possibly containing API key fragments, internal file paths, or model names) is printed directly to the console terminal. ### Suggested Fix Replace the bare handler in both `execute_plan` and `lifecycle_apply_plan` with the wrap pattern: ```python except Exception as e: if isinstance(e, (typer.Abort, typer.Exit)): raise from cleveragents.core.error_handling import classify_error, wrap_unexpected safe = wrap_unexpected(e) info = classify_error(safe) console.print( f"[red]Error [{info.code.value}] {info.code.name}:[/red] {info.message}" ) raise typer.Abort() from e ``` Also apply `redact_value()` to the `ValueError` handler at line 2494: ```python except ValueError as e: from cleveragents.shared.redaction import redact_value console.print(f"[red]Execution Error:[/red] {redact_value(str(e))}") ``` ### Category error-handling / security ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: `@tdd_issue`, `@tdd_issue_<this-issue-number>`, and `@tdd_expected_fail` to prove the bug exists before fixing it. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-09 22:47:13 +00:00
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#6645
No description provided.