[BUG] SnowflakeSearchTool masks query failures with NameError and disables retries

Open Beginner friendly
#7,655 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
74/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
python
Domain
databases

Research direction

Locate SnowflakeSearchTool._execute_query and the mocked tests covering its database failures; first reproduce the query and cursor-creation cases described in the issue. Done means the original Snowflake errors surface, retry behavior is honored for retryable failures, and connections still return to the pool.

Written by the indexing model from the issue text.

Description

Description

SnowflakeSearchTool._execute_query() classifies retryable failures with except (DatabaseError, OperationalError), but those names are imported only under TYPE_CHECKING. At runtime they do not exist, so when a query fails, evaluating the except tuple raises NameError and replaces the actual Snowflake error — retry logic never runs.

A second masking path sits in the same finally: cursor.close() runs unconditionally, so when conn.cursor() itself raises, cleanup references an unassigned local and raises UnboundLocalError, hiding the original error.

This report was prepared with AI assistance. I cannot apply repository labels as an external contributor; please add the required llm-generated label.

Steps to reproduce

  1. Construct SnowflakeSearchTool with mocked snowflake.connector.connect.
  2. Make cursor.execute raise snowflake.connector.errors.DatabaseError("query failed").
  3. Call await tool._execute_query("SELECT 1").
  4. Observe NameError: name 'DatabaseError' is not defined instead of the DatabaseError, with no retry.
  5. Make conn.cursor raise instead and observe UnboundLocalError.

Expected behavior

A database failure should propagate as the raised Snowflake error and honor the configured retry policy. A cursor-creation failure should also surface the original error. Connections should keep returning to the pool as before.

Screenshots/Code snippets

Current code:

if TYPE_CHECKING:
    from snowflake.connector.errors import (
        DatabaseError,
        OperationalError,
    )
...
except (DatabaseError, OperationalError) as e:  # NameError at runtime
...
finally:
    cursor.close()  # UnboundLocalError when conn.cursor() raised

Operating System

macOS Sonoma

Python Version

3.13 (supported by the repository; not listed in the issue template)

crewAI Version

Current main (0374c631297f)

crewAI Tools Version

Current main (0374c631297f)

Virtual Environment

Venv (uv)

Evidence

Deterministic mocked tests reproduce both masking paths on current main (NameError / UnboundLocalError) and pass once the exception classes are bound at runtime and cursor cleanup is guarded. py_compile does not catch this because the names are looked up only when an exception reaches the except clause.

Possible Solution

Import DatabaseError/OperationalError inside the existing runtime try block next to import snowflake.connector, and guard cursor cleanup with a cursor = None sentinel.

Additional context

The existing suite passes today only because the happy path never evaluates the except tuple. No matching open issue or pull request was found for this area.

Dominant language
Python
Stars
58.8k
Forks
8.5k
Avg merge
1d 13h
Merged PRs (30d)
103

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from crewAIInc/crewAI

All issues in crewAIInc/crewAI

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.