BUG-HUNT: [concurrency] Exception details mutation violates immutability in wrap_unexpected() #6926

Open
opened 2026-04-10 05:44:42 +00:00 by HAL9000 · 2 comments
Owner

Bug Report: [Concurrency] — Exception details mutation violates immutability

Severity Assessment

  • Impact: If the same CleverAgentsError exception object is accessed from multiple threads or reused, mutating its details dict could cause race conditions, data corruption, or unexpected behavior
  • Likelihood: Medium - occurs whenever wrap_unexpected() is called with a CleverAgentsError that has existing details
  • Priority: High

Location

  • File: src/cleveragents/core/error_handling.py
  • Function/Class: wrap_unexpected()
  • Lines: 296-297

Description

The wrap_unexpected() function mutates the exception object's details attribute directly when adding extra context. While the comment claims to "Create a new dict so the original details object is not mutated", the code actually mutates the exception object itself by reassigning exc.details.

Evidence

if isinstance(exc, CleverAgentsError):
    if extra_context:
        # Create a new dict so the original details object is not mutated.
        exc.details = {**exc.details, **extra_context}  # This mutates exc!
    return exc

Expected Behavior

The function should return a new CleverAgentsError instance with combined details, leaving the original exception object unchanged. This follows immutability principles and prevents side effects.

Actual Behavior

The function mutates the original exception object's details attribute, which could affect any other code holding a reference to that exception.

Suggested Fix

Create a new CleverAgentsError instance instead of mutating the original:

if isinstance(exc, CleverAgentsError):
    if extra_context:
        combined_details = {**exc.details, **extra_context}
        return CleverAgentsError(exc.message, details=combined_details)
    return exc

Category

concurrency

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.


Metadata

  • Branch: fix/concurrency-wrap-unexpected-immutability
  • Commit Message: fix(core): return new CleverAgentsError instance in wrap_unexpected() to preserve immutability
  • Milestone: Backlog
  • Parent Epic: (orphan — needs manual linking; see comment below)

Subtasks

  • Reproduce the mutation bug with a failing TDD test (@tdd_expected_fail)
  • Refactor wrap_unexpected() to construct and return a new CleverAgentsError instance instead of mutating exc.details
  • Ensure exc.__cause__ / exc.__traceback__ chaining is preserved on the new instance
  • Verify no other callers depend on identity equality of the returned exception object
  • Update docstring for wrap_unexpected() to reflect the immutability guarantee
  • Run full nox suite; confirm coverage ≥ 97%

Definition of Done

  • wrap_unexpected() never mutates the input exception object
  • A new CleverAgentsError instance is returned when extra_context is provided
  • Original exception cause chain (__cause__, __context__, __traceback__) is preserved
  • BDD unit test (tagged @tdd_issue, @tdd_issue_<issue-number>) transitions from @tdd_expected_fail to passing after the fix
  • Integration tests pass with no regressions in error propagation paths
  • All nox stages pass
  • Coverage >= 97%

Backlog note: This issue was discovered during autonomous operation
on milestone v3.5.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator

## Bug Report: [Concurrency] — Exception details mutation violates immutability ### Severity Assessment - **Impact**: If the same CleverAgentsError exception object is accessed from multiple threads or reused, mutating its details dict could cause race conditions, data corruption, or unexpected behavior - **Likelihood**: Medium - occurs whenever wrap_unexpected() is called with a CleverAgentsError that has existing details - **Priority**: High ### Location - **File**: `src/cleveragents/core/error_handling.py` - **Function/Class**: `wrap_unexpected()` - **Lines**: 296-297 ### Description The `wrap_unexpected()` function mutates the exception object's `details` attribute directly when adding extra context. While the comment claims to "Create a new dict so the original details object is not mutated", the code actually mutates the exception object itself by reassigning `exc.details`. ### Evidence ```python if isinstance(exc, CleverAgentsError): if extra_context: # Create a new dict so the original details object is not mutated. exc.details = {**exc.details, **extra_context} # This mutates exc! return exc ``` ### Expected Behavior The function should return a new `CleverAgentsError` instance with combined details, leaving the original exception object unchanged. This follows immutability principles and prevents side effects. ### Actual Behavior The function mutates the original exception object's `details` attribute, which could affect any other code holding a reference to that exception. ### Suggested Fix Create a new `CleverAgentsError` instance instead of mutating the original: ```python if isinstance(exc, CleverAgentsError): if extra_context: combined_details = {**exc.details, **extra_context} return CleverAgentsError(exc.message, details=combined_details) return exc ``` ### Category concurrency ### 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. --- ## Metadata - **Branch**: `fix/concurrency-wrap-unexpected-immutability` - **Commit Message**: `fix(core): return new CleverAgentsError instance in wrap_unexpected() to preserve immutability` - **Milestone**: Backlog - **Parent Epic**: *(orphan — needs manual linking; see comment below)* ## Subtasks - [ ] Reproduce the mutation bug with a failing TDD test (`@tdd_expected_fail`) - [ ] Refactor `wrap_unexpected()` to construct and return a new `CleverAgentsError` instance instead of mutating `exc.details` - [ ] Ensure `exc.__cause__` / `exc.__traceback__` chaining is preserved on the new instance - [ ] Verify no other callers depend on identity equality of the returned exception object - [ ] Update docstring for `wrap_unexpected()` to reflect the immutability guarantee - [ ] Run full nox suite; confirm coverage ≥ 97% ## Definition of Done - [ ] `wrap_unexpected()` never mutates the input exception object - [ ] A new `CleverAgentsError` instance is returned when `extra_context` is provided - [ ] Original exception cause chain (`__cause__`, `__context__`, `__traceback__`) is preserved - [ ] BDD unit test (tagged `@tdd_issue`, `@tdd_issue_<issue-number>`) transitions from `@tdd_expected_fail` to passing after the fix - [ ] Integration tests pass with no regressions in error propagation paths - [ ] All nox stages pass - [ ] Coverage >= 97% > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.5.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator
Author
Owner

⚠️ Orphan Issue — Needs Manual Parent Epic Linking

This issue was created by an automated bug hunter and does not currently have a parent Epic linked. Per CONTRIBUTING.md, orphan issues are not permitted.

A human reviewer should link this issue to the appropriate parent Epic using Forgejo's dependency system. The correct direction is:

This issue (#6926) BLOCKS the parent Epic (the parent Epic cannot be complete until this child is done).

Suggested parent candidates (concurrency/error-handling Epics):

  • Search for an Epic covering core/error_handling.py or general concurrency bug remediation
  • If no suitable Epic exists, one should be created first, then this issue linked to it

To link via API:

curl -s -X POST "https://git.cleverthis.com/api/v1/repos/cleveragents/cleveragents-core/issues/6926/blocks" \
  -H "Authorization: token <PAT>" \
  -H "Content-Type: application/json" \
  -d '{"owner": "cleveragents", "repo": "cleveragents-core", "index": <PARENT_EPIC_NUMBER>}'

Automated by CleverAgents Bot
Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator

⚠️ **Orphan Issue — Needs Manual Parent Epic Linking** This issue was created by an automated bug hunter and does not currently have a parent Epic linked. Per CONTRIBUTING.md, orphan issues are not permitted. A human reviewer should link this issue to the appropriate parent Epic using Forgejo's dependency system. The correct direction is: > **This issue (#6926) BLOCKS the parent Epic** (the parent Epic cannot be complete until this child is done). **Suggested parent candidates** (concurrency/error-handling Epics): - Search for an Epic covering `core/error_handling.py` or general concurrency bug remediation - If no suitable Epic exists, one should be created first, then this issue linked to it **To link via API:** ```bash curl -s -X POST "https://git.cleverthis.com/api/v1/repos/cleveragents/cleveragents-core/issues/6926/blocks" \ -H "Authorization: token <PAT>" \ -H "Content-Type: application/json" \ -d '{"owner": "cleveragents", "repo": "cleveragents-core", "index": <PARENT_EPIC_NUMBER>}' ``` --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: Bug Hunter | Agent: new-issue-creator
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High — Concurrency bug: mutating exception details dict in wrap_unexpected() can cause race conditions and data corruption in multi-threaded contexts
  • Milestone: v3.2.0 — Core error handling correctness is foundational and must be fixed early
  • Story Points: 2 — S — Fix: copy the details dict before mutation
  • MoSCoW: MoSCoW/Must have — Immutability violations in error handling can cause subtle, hard-to-debug production issues
  • Parent Epic: Needs linking to error handling epic

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

Issue triaged by project owner: - **State**: Verified - **Priority**: High — Concurrency bug: mutating exception details dict in wrap_unexpected() can cause race conditions and data corruption in multi-threaded contexts - **Milestone**: v3.2.0 — Core error handling correctness is foundational and must be fixed early - **Story Points**: 2 — S — Fix: copy the details dict before mutation - **MoSCoW**: MoSCoW/Must have — Immutability violations in error handling can cause subtle, hard-to-debug production issues - **Parent Epic**: Needs linking to error handling epic --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner
HAL9000 self-assigned this 2026-04-10 06:00:04 +00:00
HAL9000 added this to the v3.2.0 milestone 2026-04-10 06:00:04 +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#6926
No description provided.