transact-rs/sqlx · error
failed to parse DATABASE_URL
Error message
failed to parse DATABASE_URL
What it means
This panic comes from `PgConnectOptions::from_str(&url).expect(...)` inside sqlx's internal test harness (`test_context`). It fires when the DATABASE_URL environment variable is set but is not a valid PostgreSQL connection URL that can be parsed into PgConnectOptions. Since sqlx uses `.expect`, it is a hard panic, not a recoverable error.
Source
Thrown at sqlx-postgres/src/testing/mod.rs:95
.bind(&deleted_db_names)
.execute(&mut conn)
.await?;
let _ = conn.close().await;
Ok(Some(delete_db_names.len()))
}
async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {
// TODO: I want to get the testing feature out the door so this will have to wait,
// but I'm keeping the code around for now because I plan to come back to it.
todo!()
}
}
async fn test_context(args: &TestArgs) -> Result<TestContext<Postgres>, Error> {
let url = dotenvy::var("DATABASE_URL").expect("DATABASE_URL must be set");
let master_opts = PgConnectOptions::from_str(&url).expect("failed to parse DATABASE_URL");
let pool = PoolOptions::new()
// Postgres' normal connection limit is 100 plus 3 superuser connections
// We don't want to use the whole cap and there may be fuzziness here due to
// concurrently running tests anyway.
.max_connections(20)
// Immediately close master connections. Tokio's I/O streams don't like hopping runtimes.
.after_release(|_conn, _| Box::pin(async move { Ok(false) }))
.connect_lazy_with(master_opts);
let master_pool = match once_lock_try_insert_polyfill(&MASTER_POOL, pool) {
Ok(inserted) => inserted,
Err((existing, pool)) => {
// Sanity checks.
assert_eq!(
existing.connect_options().host,
pool.connect_options().host,
"DATABASE_URL changed at runtime, host differs"View on GitHub (pinned to 03af8bcc57)
Solutions
- Fix DATABASE_URL so it is a valid Postgres URL, e.g. `postgres://user:password@host:5432/db`
- Percent-encode special characters in the username/password (e.g. `@` -> `%40`, `#` -> `%23`)
- Verify the variable is actually set and non-empty: `echo $DATABASE_URL` (shell quoting may have mangled it)
- Ensure the scheme is postgres:// or postgresql://, not another database's scheme
- If you are a sqlx user (not contributor), note this is the internal test harness — write your own pool setup instead of relying on sqlx's test module
Example fix
// before DATABASE_URL=postgres@localhost/mydb // malformed, missing :// // after DATABASE_URL=postgres://postgres:password@localhost:5432/mydb
Defensive patterns
Strategy: validation
Validate before calling
fn validate_database_url() -> Result<String, String> {
match std::env::var("DATABASE_URL") {
Ok(url) if !url.trim().is_empty() => {
if url.starts_with("postgres://") || url.starts_with("postgresql://") {
Ok(url)
} else {
Err(format!("DATABASE_URL has unsupported/missing scheme: {url}"))
}
}
Ok(_) => Err("DATABASE_URL is empty".into()),
Err(_) => Err("DATABASE_URL is not set".into()),
}
} Try / catch
let url = validate_database_url().unwrap_or_else(|e| panic!("{e}: set a valid postgres:// URL in .env")); Prevention
- Validate DATABASE_URL at startup before running tests
- Keep a checked-in .env.example with a known-good URL shape
- Percent-encode credentials with special characters
- Use PgConnectOptions::new().host(...).user(...) instead of URL parsing to avoid parse failures
When it happens
Trigger: Calling `test_context(args)` (sqlx's internal test helper) while DATABASE_URL is set to a malformed string — missing scheme (not postgres:// or postgresql://), bad characters, invalid percent-encoding, or garbage text.
Common situations: CI or local test environments where DATABASE_URL is set to an empty string, contains typos (e.g. missing `://`), has unescaped special characters in the password, or points to a non-Postgres scheme like `mysql://`. Also common when .env files are stale or overwritten by CI variables.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- DATABASE_URL must be set
- PgBindIter is only used once
- unimplemented!()
- VARBIT length mismatch.
- DATABASE_URL must be set
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/30375e07a28179b0.
Report an issue: GitHub.