{"record":{"id":"4405e4ca4310685e","repo":"block/buzz","slug":"connect-desired-schema-scratch-db","errorCode":null,"errorMessage":"connect desired-schema scratch db","messagePattern":"connect desired-schema scratch db","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-db/src/store/channel_members.rs","lineNumber":3141,"sourceCode":"\n        let admin = PgPool::connect(&admin_url().await)\n            .await\n            .expect(\"connect admin\");\n        let scratch_name = format!(\"schema_roster_role_{}\", Uuid::new_v4().simple());\n        sqlx::query(sqlx::AssertSqlSafe(format!(\n            \"CREATE DATABASE {scratch_name}\"\n        )))\n        .execute(&admin)\n        .await\n        .expect(\"create desired-schema scratch db\");\n        let base_url = admin_url().await;\n        let slash = base_url.rfind('/').expect(\"database URL has path segment\");\n        let scratch_url = format!(\"{}/{}\", &base_url[..slash], scratch_name);\n        let pool = PgPoolOptions::new()\n            .max_connections(1)\n            .connect(&scratch_url)\n            .await\n            .expect(\"connect desired-schema scratch db\");\n        sqlx::raw_sql(include_str!(\"../../../../schema/schema.sql\"))\n            .execute(&pool)\n            .await\n            .expect(\"apply desired-state schema\");\n\n        let db = Db::from_pool(pool.clone());\n        let community_uuid = Uuid::new_v4();\n        let community = CommunityId::from_uuid(community_uuid);\n        let channel = Uuid::new_v4();\n        let relay_keys = Keys::generate();\n        let owner_keys = Keys::generate();\n        let owner = owner_keys.public_key().to_bytes();\n        seed_community_channel(&pool, community_uuid, channel, &owner_keys).await;\n        let member = Keys::generate().public_key().to_bytes();\n        sqlx::query(\n            \"INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by) \\\n             VALUES ($1, $2, $3, 'admin', $4)\",\n        )","sourceCodeStart":3123,"sourceCodeEnd":3159,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/crates/buzz-db/src/store/channel_members.rs#L3123-L3159","documentation":"After creating the scratch database, the test opens a single-connection pool to it. The expect panics when connecting to the freshly created scratch_url fails — most often because Postgres is still finishing CREATE DATABASE bookkeeping, the scratch name in the URL is wrong (see the rfind split), or the createdb was rolled back.","triggerScenarios":"PgPoolOptions::connect(&scratch_url) fails when the scratch URL is malformed by the string split, the database was dropped between creation and connect, or credentials valid on the admin DB lack CONNECT on the new database (default is PUBLIC CONNECT, so this usually means bad password/host).","commonSituations":"URL path-splitting bug producing postgres://host/ (empty db); firewall/pg_hba rules; password auth failing on the new db; hitting a pooler (pgbouncer) that does not know the new database yet.","solutions":["Fix the URL construction to use Url::set_path so the scratch name is placed correctly","Verify the database exists: psql '<admin_url>' -c '\\l' | grep <scratch_name>","Check the scratch_url string right before connect — it must be {base}/postgres replaced with {base}/{scratch_name}","Wait/retry briefly if connecting immediately after CREATE DATABASE in a race-prone environment"],"exampleFix":"// before\nlet scratch_url = format!(\"{}/{}\", &base_url[..slash], scratch_name);\nlet pool = PgPoolOptions::new().max_connections(1).connect(&scratch_url).await.expect(\"connect desired-schema scratch db\");\n// after\nassert!(!scratch_url.ends_with('/'), \"scratch URL has empty database name: {scratch_url}\");\nlet pool = PgPoolOptions::new().max_connections(1).connect(&scratch_url).await\n    .expect(\"connect desired-schema scratch db\");","handlingStrategy":"validation","validationCode":"assert!(!scratch_url.ends_with('/'), \"scratch URL has empty db name: {scratch_url}\");\nlet exists: bool = sqlx::query_scalar(&format!(\"SELECT EXISTS (SELECT 1 FROM pg_database WHERE datname = '{scratch_name}')\")).fetch_one(&admin).await?;","typeGuard":"fn scratch_url_well_formed(u: &str, name: &str) -> bool {\n    url::Url::parse(u).map(|p| p.path() == format!(\"/{name}\")).unwrap_or(false)\n}","tryCatchPattern":"let pool = PgPoolOptions::new().max_connections(1).connect(&scratch_url).await\n    .unwrap_or_else(|e| panic!(\"connect scratch db '{scratch_url}' failed: {e}\"));","preventionTips":["Build URLs with url::Url, never string concatenation on rfind slices","Confirm CREATE DATABASE succeeded via pg_database before connecting","Avoid poolers like pgbouncer for scratch databases"],"tags":["postgres","connection","url-parsing"],"backgroundTag":"connection-refused","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-08-30T13:49:18.474Z","contentChangedAt":"2026-08-30T13:49:18.474Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}