crewAIInc/crewAI · error · ValueError
Failed to load data from PostgreSQL: {e}
Error message
Failed to load data from PostgreSQL: {e} What it means
The catch-all ValueError from PGFileLoader for any non-database exception during loading — most often connection failures raised before or during psycopg connect(): unknown hostname, refused connection, authentication failure, or missing psycopg driver. It wraps the original exception, so __cause__ carries the real reason.
Source
Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/postgres_loader.py:101
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
- Inspect the wrapped exception: except ValueError as e: print(e.__cause__) to get the underlying connection error.
- Verify connectivity out-of-band: psql 'postgresql://user:pass@host:5432/db' -c 'select 1' from the same machine/container.
- URL-encode special characters in the password (use urllib.parse.quote) or avoid them in the URI.
- If the server requires TLS, append ?sslmode=require to the URI.
- From Docker, replace localhost with the service name or host.docker.internal as appropriate.
Example fix
# before
db_uri = "postgresql://user:p@ssw0rd@host:5432/db" # '@' in password breaks parsing
# after
from urllib.parse import quote
db_uri = f"postgresql://user:{quote('p@ssw0rd')}@host:5432/db" Defensive patterns
Strategy: retry
Validate before calling
import psycopg
def can_connect(db_uri: str) -> bool:
try:
with psycopg.connect(db_uri, connect_timeout=5):
return True
except Exception:
return False Try / catch
for attempt in range(3):
try:
result = pg_loader.load(src, metadata=md)
break
except ValueError as e:
if "Failed to load" in str(e) and is_transient(e.__cause__):
backoff(attempt)
continue
raise Prevention
- URL-encode passwords: urllib.parse.quote(password, safe='').
- Add sslmode=require when the server enforces TLS.
- Use a pre-flight connectivity check in orchestration before batch loads.
- Log e.__cause__ always — the outer message hides the real network reason.
When it happens
Trigger: Network-level failures: host unreachable, wrong port, postgres not running, TLS requirement mismatch, or psycopg.OperationalError on bad credentials that is not an instance of the caught Error class path. Also triggered if the psycopg package itself is missing or incompatible.
Common situations: Connecting from a container to a DB on 'localhost' when the DB runs on the host (need host.docker.internal); DB behind a VPN not connected; password with special characters not URL-encoded in the URI; server requires SSL (sslmode=require) which the bare URI omits.
Related errors
- Deployment status response did not include a uuid
- MySQL database error: {e}
- Database URI is required for PostgreSQL loader
- Invalid PostgreSQL URI scheme: {parsed.scheme}
- Database name is required in the URI
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/af873464b9dcd01c.
Report an issue: GitHub.