crewAIInc/crewAI · error · RuntimeError

Failed to fetch tables: {result}

Error message

Failed to fetch tables: {result}

What it means

NL2SQLTool's model_post_init calls _fetch_available_tables() to introspect the database schema at construction time; that helper returns a string (an error message) instead of a table list when SQLAlchemy cannot read the catalog. When the result is a str, the tool raises RuntimeError wrapping that message. So the real cause (bad URI, unreachable server, permissions) is inside {result}.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/nl2sql/nl2sql_tool.py:281

        return self

    def model_post_init(self, __context: Any) -> None:
        if not SQLALCHEMY_AVAILABLE:
            raise ImportError(
                "sqlalchemy is not installed. Please install it with "
                "`pip install crewai-tools[sqlalchemy]`"
            )

        if self.allow_dml:
            logger.warning(
                "NL2SQLTool: allow_dml=True — write operations (INSERT/UPDATE/"
                "DELETE/DROP/…) are permitted. Use with caution."
            )

        data: dict[str, list[dict[str, Any]] | str] = {}
        result = self._fetch_available_tables()
        if isinstance(result, str):
            raise RuntimeError(f"Failed to fetch tables: {result}")
        tables: list[dict[str, Any]] = result

        for table in tables:
            table_columns = self._fetch_all_available_columns(table["table_name"])
            data[f"{table['table_name']}_columns"] = table_columns

        self.tables = tables
        self.columns = data

    # Query validation

    def _validate_query(self, sql_query: str) -> None:
        """Raise ValueError if *sql_query* is not permitted under the current config.

        Splits the query on semicolons and validates each statement
        independently.  When ``allow_dml=False`` (the default), multi-statement
        queries are rejected outright to prevent ``SELECT 1; DROP TABLE users``
        style bypasses.  When ``allow_dml=True`` every statement is checked and

View on GitHub (pinned to 754d7323be)

Solutions

  1. Read the {result} text inside the RuntimeError message — it contains the underlying SQLAlchemy/DBAPI error; fix that root cause first.
  2. Verify connectivity with the same URI from a plain SQLAlchemy engine: sqlalchemy.create_engine(uri).connect().
  3. Check the URI format, e.g. postgresql+psycopg2://user:pass@host:5432/dbname, and URL-encode special characters in the password.
  4. Install the missing DB driver if the message mentions one (pip install psycopg2-binary / pymysql / cx_Oracle).
  5. Ensure the DB user can query the catalog (information_schema.tables / pg_catalog).

Example fix

# before
NL2SQLTool(db_uri="postgres://user:pass@localhost:5432/db")

# after
NL2SQLTool(db_uri="postgresql+psycopg2://user:p%40ss@localhost:5432/db")
Defensive patterns

Strategy: try-catch

Validate before calling

from sqlalchemy import create_engine, text

def db_reachable(db_uri: str) -> tuple[bool, str]:
    try:
        eng = create_engine(db_uri)
        with eng.connect() as c:
            c.execute(text("SELECT 1"))
        return True, ""
    except Exception as e:
        return False, str(e)

ok, err = db_reachable(uri)
if not ok:
    raise SystemExit(f"db_uri not usable: {err}")

Type guard

def is_valid_db_uri(uri: str) -> bool:
    try:
        from sqlalchemy.engine import make_url
        make_url(uri)
        return True
    except Exception:
        return False

Try / catch

try:
    tool = NL2SQLTool(db_uri=uri)
except RuntimeError as e:
    # message embeds the underlying SQLAlchemy error
    raise SystemExit(f"NL2SQLTool init failed: {e}") from e

Prevention

When it happens

Trigger: Instantiating NL2SQLTool(db_uri=...) when: the DB server is down or unreachable, the URI scheme/driver is malformed or its driver (e.g. psycopg2, pymysql) is missing, credentials are wrong, or the user has no permission to read information_schema/pg_catalog.

Common situations: Typos in the db_uri (wrong port, missing dialect prefix like postgresql+psycopg2://), running against a local SQLite file path that does not exist, Docker container DB not yet started when the tool is constructed, or a misquoted password with special characters in the URI.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/3134cf00f58a6592. Report an issue: GitHub.