{"record":{"id":"30375e07a28179b0","repo":"transact-rs/sqlx","slug":"failed-to-parse-database-url-30375e","errorCode":null,"errorMessage":"failed to parse DATABASE_URL","messagePattern":"failed to parse DATABASE_URL","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx-postgres/src/testing/mod.rs","lineNumber":95,"sourceCode":"            .bind(&deleted_db_names)\n            .execute(&mut conn)\n            .await?;\n\n        let _ = conn.close().await;\n        Ok(Some(delete_db_names.len()))\n    }\n\n    async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {\n        // TODO: I want to get the testing feature out the door so this will have to wait,\n        // but I'm keeping the code around for now because I plan to come back to it.\n        todo!()\n    }\n}\n\nasync fn test_context(args: &TestArgs) -> Result<TestContext<Postgres>, Error> {\n    let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n    let master_opts = PgConnectOptions::from_str(&url).expect(\"failed to parse DATABASE_URL\");\n\n    let pool = PoolOptions::new()\n        // Postgres' normal connection limit is 100 plus 3 superuser connections\n        // We don't want to use the whole cap and there may be fuzziness here due to\n        // concurrently running tests anyway.\n        .max_connections(20)\n        // Immediately close master connections. Tokio's I/O streams don't like hopping runtimes.\n        .after_release(|_conn, _| Box::pin(async move { Ok(false) }))\n        .connect_lazy_with(master_opts);\n\n    let master_pool = match once_lock_try_insert_polyfill(&MASTER_POOL, pool) {\n        Ok(inserted) => inserted,\n        Err((existing, pool)) => {\n            // Sanity checks.\n            assert_eq!(\n                existing.connect_options().host,\n                pool.connect_options().host,\n                \"DATABASE_URL changed at runtime, host differs\"","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-postgres/src/testing/mod.rs#L77-L113","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nDATABASE_URL=postgres@localhost/mydb   // malformed, missing ://\n// after\nDATABASE_URL=postgres://postgres:password@localhost:5432/mydb","handlingStrategy":"validation","validationCode":"fn validate_database_url() -> Result<String, String> {\n    match std::env::var(\"DATABASE_URL\") {\n        Ok(url) if !url.trim().is_empty() => {\n            if url.starts_with(\"postgres://\") || url.starts_with(\"postgresql://\") {\n                Ok(url)\n            } else {\n                Err(format!(\"DATABASE_URL has unsupported/missing scheme: {url}\"))\n            }\n        }\n        Ok(_) => Err(\"DATABASE_URL is empty\".into()),\n        Err(_) => Err(\"DATABASE_URL is not set\".into()),\n    }\n}","typeGuard":null,"tryCatchPattern":"let url = validate_database_url().unwrap_or_else(|e| panic!(\"{e}: set a valid postgres:// URL in .env\"));","preventionTips":["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"],"tags":["rust","sqlx","postgres","env-var","panic"],"backgroundTag":"invalid-database-url","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}