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 andView on GitHub (pinned to 754d7323be)
Solutions
- Read the {result} text inside the RuntimeError message — it contains the underlying SQLAlchemy/DBAPI error; fix that root cause first.
- Verify connectivity with the same URI from a plain SQLAlchemy engine: sqlalchemy.create_engine(uri).connect().
- Check the URI format, e.g. postgresql+psycopg2://user:pass@host:5432/dbname, and URL-encode special characters in the password.
- Install the missing DB driver if the message mentions one (pip install psycopg2-binary / pymysql / cx_Oracle).
- 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
- Validate db_uri with sqlalchemy.engine.make_url before constructing the tool.
- Smoke-test connectivity with create_engine(uri).connect() in startup checks.
- Fail fast at app start rather than constructing NL2SQLTool lazily inside agent runs.
- URL-encode passwords containing @ : / characters.
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
- Deployment status response did not include a uuid
- Failed to load data from PostgreSQL: {e}
- sqlalchemy is not installed. Please install it with `pip ins
- Project name cannot be empty
- Project name '{name}' produces invalid folder name '{folder_
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/3134cf00f58a6592.
Report an issue: GitHub.