crewAIInc/crewAI · error · ValueError
PostgreSQL database error: {e}
Error message
PostgreSQL database error: {e} What it means
Thrown by PGFileLoader when psycopg raises a database-level Error while executing the query or fetching rows: bad SQL syntax, missing tables/columns, permission denied on a relation, or a query cancelled by statement_timeout. It wraps psycopg3's Error hierarchy into ValueError, preserving the original as __cause__.
Source
Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/postgres_loader.py:99
content = "\n".join(text_parts)
if len(content) > 100000:
content = content[:100000] + "\n\n[Content truncated...]"
return LoaderResult(
content=content,
metadata={
"source": query,
"database": connection_params["database"],
"row_count": len(rows),
"columns": columns,
},
doc_id=self.generate_doc_id(source_ref=query, content=content),
)
finally:
connection.close()
except Error as e:
raise ValueError(f"PostgreSQL database error: {e}") from e
except Exception as e:
raise ValueError(f"Failed to load data from PostgreSQL: {e}") from e
View on GitHub (pinned to 754d7323be)
Solutions
- Run the exact query manually with psql or a DB client using the same credentials to see the real error, then fix the SQL.
- Confirm the table/view exists in the target database and the URI user has SELECT privilege on it.
- For long queries, raise statement_timeout on the role or session, or pre-aggregate the data.
- Catch ValueError and inspect e.__cause__ — it is the original psycopg Error with the server's SQLSTATE details.
Example fix
# before result = loader.load(SourceContent(source="SELECT * FROM user"), metadata=md) # typo: users # after result = loader.load(SourceContent(source="SELECT id, name FROM users LIMIT 1000"), metadata=md)
Defensive patterns
Strategy: validation
Validate before calling
import psycopg
def query_is_valid(conn_string: str, query: str) -> bool:
with psycopg.connect(conn_string) as conn:
conn.execute("SELECT 1 FROM (" + query.rstrip(';') + ") q LIMIT 0")
return True # raises on bad SQL/permissions Try / catch
try:
result = pg_loader.load(src, metadata=md)
except ValueError as e:
cause = e.__cause__
if "database error" in str(e).lower():
log.error("SQL failed: %s", getattr(cause, "diag", None) or cause) Prevention
- Validate SQL against the same database/role before handing it to the loader.
- Prefer explicit column lists over SELECT * so schema drift fails your tests first.
- Read e.__cause__ for the SQLSTATE diag instead of parsing the wrapped message.
When it happens
Trigger: The source string passed to load() is executed verbatim via cursor.execute(query). Typos in SQL, referencing tables that do not exist in the target database, insufficient privileges, or queries that exceed server-side timeouts all surface here. Because the query text is interpolated nowhere, SQL values with parameters (e.g. expecting %s binding) will also fail.
Common situations: Pointing the loader at production where table names differ from staging; using SELECT * on views the service role cannot read; long analytical queries hitting statement_timeout; copy-pasting interactive psql SQL that contains psql-only syntax (\\d, ; handled differently).
Related errors
- Database URI is required for PostgreSQL loader
- MySQL database error: {e}
- Invalid PostgreSQL URI scheme: {parsed.scheme}
- Database name is required in the URI
- Failed to load data from PostgreSQL: {e}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/1ac52c9a45c4700c.
Report an issue: GitHub.