BUG-HUNT: [boundary-condition] CircuitBreaker missing validation for failure_threshold <= 0 #7747

Open
opened 2026-04-12 03:23:02 +00:00 by HAL9000 · 3 comments
Owner

Bug Report: Boundary Condition — CircuitBreaker Missing Validation for failure_threshold

Severity Assessment

  • Impact: A CircuitBreaker instantiated with failure_threshold=0 or a negative value will open on the very first failure (or even unexpectedly), regardless of intent. Silent misconfiguration with no ValueError raised, unlike the validated half_open_max_successes parameter.
  • Likelihood: Low — only affects callers who pass an invalid failure_threshold, but the lack of validation means the misconfiguration is silent and hard to debug.
  • Priority: Medium

Location

  • File: src/cleveragents/core/circuit_breaker.py
  • Function/Class: CircuitBreaker.__init__
  • Lines: 56–107

Description

The CircuitBreaker.__init__ validates half_open_max_successes (raises ValueError if < 1), but performs no equivalent validation on failure_threshold. The parameter docstring states it "must be a positive integer", but this contract is never enforced.

In _on_failure (CLOSED state), the check is:

self.failure_count += 1
if self.failure_count >= self.failure_threshold:
    self.state = CircuitBreakerState.OPEN

With failure_threshold=0: after the first failure failure_count becomes 1, and 1 >= 0 is True, so the circuit opens immediately. The parameter effectively acts as if failure_threshold=1.

With failure_threshold=-1 (or any negative): same behavior — circuit opens on first failure.

This is inconsistent with the half_open_max_successes validation, which does raise a ValueError for values < 1.

Evidence

# src/cleveragents/core/circuit_breaker.py lines 86-107
if half_open_max_successes < 1:
    raise ValueError("half_open_max_successes must be >= 1")
self.failure_threshold = failure_threshold  # BUG: no validation
self.recovery_timeout = recovery_timeout   # BUG: no validation
...

# _on_failure (lines 396-401)
self.failure_count += 1
self.last_failure_time = time.monotonic()
if self.failure_count >= self.failure_threshold:  # 1 >= 0 = True with threshold=0
    self.state = CircuitBreakerState.OPEN
    return True

Additionally, recovery_timeout has no validation — a value of 0.0 or negative would cause the circuit to immediately attempt reset from OPEN to HALF_OPEN on every call, effectively disabling the circuit breaker's recovery timeout.

Expected Behavior

Instantiating CircuitBreaker(failure_threshold=0) or CircuitBreaker(failure_threshold=-1) should raise a ValueError, consistent with how half_open_max_successes < 1 is handled. Similarly, recovery_timeout <= 0 should raise a ValueError.

Actual Behavior

No error is raised. The circuit breaker silently uses the invalid value, leading to unexpected circuit-open behavior that is difficult to diagnose.

Suggested Fix

def __init__(self, failure_threshold: int = 5, recovery_timeout: float = 60.0, ...):
    if half_open_max_successes < 1:
        raise ValueError("half_open_max_successes must be >= 1")
    if failure_threshold < 1:
        raise ValueError("failure_threshold must be >= 1")
    if recovery_timeout <= 0:
        raise ValueError("recovery_timeout must be a positive number")
    ...

Category

boundary-condition

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD.


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

## Bug Report: Boundary Condition — CircuitBreaker Missing Validation for failure_threshold ### Severity Assessment - **Impact**: A `CircuitBreaker` instantiated with `failure_threshold=0` or a negative value will open on the very first failure (or even unexpectedly), regardless of intent. Silent misconfiguration with no ValueError raised, unlike the validated `half_open_max_successes` parameter. - **Likelihood**: Low — only affects callers who pass an invalid `failure_threshold`, but the lack of validation means the misconfiguration is silent and hard to debug. - **Priority**: Medium ### Location - **File**: `src/cleveragents/core/circuit_breaker.py` - **Function/Class**: `CircuitBreaker.__init__` - **Lines**: 56–107 ### Description The `CircuitBreaker.__init__` validates `half_open_max_successes` (raises `ValueError` if `< 1`), but performs no equivalent validation on `failure_threshold`. The parameter docstring states it "must be a positive integer", but this contract is never enforced. In `_on_failure` (CLOSED state), the check is: ```python self.failure_count += 1 if self.failure_count >= self.failure_threshold: self.state = CircuitBreakerState.OPEN ``` With `failure_threshold=0`: after the first failure `failure_count` becomes 1, and `1 >= 0` is `True`, so the circuit opens immediately. The parameter effectively acts as if `failure_threshold=1`. With `failure_threshold=-1` (or any negative): same behavior — circuit opens on first failure. This is inconsistent with the `half_open_max_successes` validation, which does raise a `ValueError` for values `< 1`. ### Evidence ```python # src/cleveragents/core/circuit_breaker.py lines 86-107 if half_open_max_successes < 1: raise ValueError("half_open_max_successes must be >= 1") self.failure_threshold = failure_threshold # BUG: no validation self.recovery_timeout = recovery_timeout # BUG: no validation ... # _on_failure (lines 396-401) self.failure_count += 1 self.last_failure_time = time.monotonic() if self.failure_count >= self.failure_threshold: # 1 >= 0 = True with threshold=0 self.state = CircuitBreakerState.OPEN return True ``` Additionally, `recovery_timeout` has no validation — a value of `0.0` or negative would cause the circuit to immediately attempt reset from OPEN to HALF_OPEN on every call, effectively disabling the circuit breaker's recovery timeout. ### Expected Behavior Instantiating `CircuitBreaker(failure_threshold=0)` or `CircuitBreaker(failure_threshold=-1)` should raise a `ValueError`, consistent with how `half_open_max_successes < 1` is handled. Similarly, `recovery_timeout <= 0` should raise a `ValueError`. ### Actual Behavior No error is raised. The circuit breaker silently uses the invalid value, leading to unexpected circuit-open behavior that is difficult to diagnose. ### Suggested Fix ```python def __init__(self, failure_threshold: int = 5, recovery_timeout: float = 60.0, ...): if half_open_max_successes < 1: raise ValueError("half_open_max_successes must be >= 1") if failure_threshold < 1: raise ValueError("failure_threshold must be >= 1") if recovery_timeout <= 0: raise ValueError("recovery_timeout must be a positive number") ... ``` ### Category boundary-condition ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-12 03:44:26 +00:00
Author
Owner

Verified — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: CircuitBreaker missing validation for failure_threshold <= 0. MoSCoW: Should-have. Priority: Medium. --- **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#7747
No description provided.