BUG-HUNT: [error-handling] ActorRegistry.add() swallows NotFoundError from actor existence check allowing silent failures during add validation #7379

Open
opened 2026-04-10 18:35:26 +00:00 by HAL9000 · 3 comments
Owner

Bug Report: [error-handling] ActorRegistry.add() catches all exceptions when checking for existing actors, swallowing genuine errors

Severity Assessment

  • Impact: When get_actor(name) raises a database error (not just NotFoundError), the add() method silently treats it as "actor not found" and proceeds to create a potentially duplicate actor, potentially corrupting the database state
  • Likelihood: Medium — database errors during actor lookups can happen during high load, transient SQLite locks, or connection issues
  • Priority: Medium

Location

  • File: src/cleveragents/actor/registry.py
  • Function/Class: ActorRegistry.add()
  • Lines: ~165-185

Description

The ActorRegistry.add() method has a subtle bug in its duplicate-check logic:

# Check for existing actor when not updating
if not update:
    try:
        self._actor_service.get_actor(name)
        raise ValidationError(
            f"Actor '{name}' already exists. Pass update=True to overwrite."
        )
    except Exception as exc:
        if "already exists" in str(exc):
            raise
        # NotFoundError is expected for new actors

This code:

  1. Calls get_actor(name) to check if the actor already exists
  2. If it exists, the call succeeds and raises ValidationError("already exists")
  3. If it doesn't exist, get_actor(name) raises NotFoundError (or similar)
  4. The except Exception catches all exceptions, not just NotFoundError
  5. It only re-raises the exception if "already exists" is in the message
  6. For any other exception (database error, network error, etc.), the code silently continues as if the actor doesn't exist!

This means if get_actor() raises a sqlalchemy.exc.OperationalError: database is locked, the check silently passes, and add() proceeds to create the actor even though the existence check failed.

Evidence

def add(self, yaml_text: str, *, update: bool = False, ...) -> Actor:
    # ...
    # Check for existing actor when not updating
    if not update:
        try:
            self._actor_service.get_actor(name)
            raise ValidationError(
                f"Actor '{name}' already exists. Pass update=True to overwrite."
            )
        except Exception as exc:
            if "already exists" in str(exc):
                raise
            # NotFoundError is expected for new actors
            # BUG: All other exceptions (DB errors, etc.) are silently swallowed!

The correct pattern should only catch NotFoundError (or the specific exception type for "not found"), not all Exception:

from cleveragents.core.exceptions import NotFoundError  # or whatever the correct exception is

if not update:
    try:
        self._actor_service.get_actor(name)
        raise ValidationError(
            f"Actor '{name}' already exists. Pass update=True to overwrite."
        )
    except NotFoundError:
        pass  # Actor doesn't exist, proceed with creation
    # All other exceptions propagate naturally

Expected Behavior

The existence check should only catch NotFoundError (the expected "not found" case). All other exceptions should propagate to the caller.

Actual Behavior

The except Exception clause catches all exceptions, swallowing database errors and treating them as "actor not found", which allows add() to proceed when the existence check was unreliable.

Category

error-handling

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_, and @tdd_expected_fail to prove the bug exists before fixing it.


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

## Bug Report: [error-handling] ActorRegistry.add() catches all exceptions when checking for existing actors, swallowing genuine errors ### Severity Assessment - **Impact**: When `get_actor(name)` raises a database error (not just `NotFoundError`), the `add()` method silently treats it as "actor not found" and proceeds to create a potentially duplicate actor, potentially corrupting the database state - **Likelihood**: Medium — database errors during actor lookups can happen during high load, transient SQLite locks, or connection issues - **Priority**: Medium ### Location - **File**: `src/cleveragents/actor/registry.py` - **Function/Class**: `ActorRegistry.add()` - **Lines**: ~165-185 ### Description The `ActorRegistry.add()` method has a subtle bug in its duplicate-check logic: ```python # Check for existing actor when not updating if not update: try: self._actor_service.get_actor(name) raise ValidationError( f"Actor '{name}' already exists. Pass update=True to overwrite." ) except Exception as exc: if "already exists" in str(exc): raise # NotFoundError is expected for new actors ``` This code: 1. Calls `get_actor(name)` to check if the actor already exists 2. If it exists, the call succeeds and raises `ValidationError("already exists")` 3. If it doesn't exist, `get_actor(name)` raises `NotFoundError` (or similar) 4. The `except Exception` catches **all exceptions**, not just `NotFoundError` 5. It only re-raises the exception if `"already exists"` is in the message 6. For any other exception (database error, network error, etc.), the code silently continues as if the actor doesn't exist! This means if `get_actor()` raises a `sqlalchemy.exc.OperationalError: database is locked`, the check silently passes, and `add()` proceeds to create the actor even though the existence check failed. ### Evidence ```python def add(self, yaml_text: str, *, update: bool = False, ...) -> Actor: # ... # Check for existing actor when not updating if not update: try: self._actor_service.get_actor(name) raise ValidationError( f"Actor '{name}' already exists. Pass update=True to overwrite." ) except Exception as exc: if "already exists" in str(exc): raise # NotFoundError is expected for new actors # BUG: All other exceptions (DB errors, etc.) are silently swallowed! ``` The correct pattern should only catch `NotFoundError` (or the specific exception type for "not found"), not all `Exception`: ```python from cleveragents.core.exceptions import NotFoundError # or whatever the correct exception is if not update: try: self._actor_service.get_actor(name) raise ValidationError( f"Actor '{name}' already exists. Pass update=True to overwrite." ) except NotFoundError: pass # Actor doesn't exist, proceed with creation # All other exceptions propagate naturally ``` ### Expected Behavior The existence check should only catch `NotFoundError` (the expected "not found" case). All other exceptions should propagate to the caller. ### Actual Behavior The `except Exception` clause catches all exceptions, swallowing database errors and treating them as "actor not found", which allows `add()` to proceed when the existence check was unreliable. ### Category error-handling ### 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 Detection Pool | Agent: bug-hunt-pool-supervisor
Author
Owner

Verified — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — Bug: ActorRegistry.add() swallows NotFoundError allowing silent failures. 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#7379
No description provided.