{"record":{"id":"23d0591e16d41427","repo":"nautechsystems/nautilus_trader","slug":"error-dropping-role-database-e","errorCode":null,"errorMessage":"Error dropping role {database}: {e:?}","messagePattern":"Error dropping role (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/pg.rs","lineNumber":660,"sourceCode":"        .execute(pg)\n        .await\n    {\n        Ok(_) => log::info!(\"Dropped schema public\"),\n        Err(e) => log::error!(\"Error dropping schema public: {e:?}\"),\n    }\n\n    // Drop role\n    match sqlx::query(AssertSqlSafe(format!(\"DROP ROLE IF EXISTS {database};\")))\n        .execute(pg)\n        .await\n    {\n        Ok(_) => log::info!(\"Dropped role {database}\"),\n        Err(e) => {\n            let err_msg = e.to_string();\n            if err_msg.contains(\"55006\") || err_msg.contains(\"current user cannot be dropped\") {\n                log::warn!(\"Cannot drop currently connected role {database}\");\n            } else {\n                anyhow::bail!(\"Error dropping role {database}: {e:?}\");\n            }\n        }\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use rstest::rstest;\n\n    use super::*;\n\n    #[rstest]\n    fn test_postgres_connect_options_toml_round_trip() {\n        let config: PostgresConnectOptions = toml::from_str(\n            r#\"\nhost = \"localhost\"\nport = 5432","sourceCodeStart":642,"sourceCodeEnd":678,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/pg.rs#L642-L678","documentation":"drop_postgres removes the per-database role after dropping the database. If the DROP ROLE statement fails and the error is not one of the tolerated cases (SQLSTATE 55006 'role is currently in use' / 'current user cannot be dropped'), the function bails with this error, typically because the role still owns objects or other sessions remain connected.","triggerScenarios":"Calling drop_postgres (via run_database_command drop) when the role still owns objects in other databases (SQLSTATE 2BP01 dependent objects), the role is the current session user, or other active connections hold sessions open with a different error signature.","commonSituations":"Leftover application connections keeping the role's database in use; the role owning objects in shared databases; running the drop command while connected as the role being dropped; CI environments where a previous test run's pool was not fully closed.","solutions":["Check the embedded error {e:?} for SQLSTATE: terminate remaining connections first (e.g. SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = '<role>') then retry","Reassign or drop objects owned by the role in other databases (REASSIGN OWNED BY ... / DROP OWNED BY ...) before dropping the role","Ensure you are not connected as the role being dropped; run the drop as a superuser or different admin role","If the tolerated 55006 path was expected, verify no pool or client still holds an open connection before invoking drop_postgres"],"exampleFix":"// before: role still owns objects -> bail\n\"Error dropping role nautilus_trading: DbError { code: \\\"2BP01\\\", ... }\"\n// after\nREASSIGN OWNED BY nautilus_trading TO postgres;\nDROP OWNED BY nautilus_trading;\nDROP ROLE nautilus_trading;","handlingStrategy":"validation","validationCode":"// pre-check for active sessions of the role before dropping\nSELECT count(*) FROM pg_stat_activity WHERE usename = '<role>';\n// pre-check dependent objects\nSELECT count(*) FROM pg_class WHERE relowner = 'postgres'::regoper; -- substitute role oid","typeGuard":null,"tryCatchPattern":"match drop_postgres(&pool, &database).await {\n    Ok(_) => {},\n    Err(e) if e.to_string().contains(\"Error dropping role\") => {\n        // terminate backends / DROP OWNED, then retry once\n        log::warn!(\"role drop blocked: {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Close all connection pools and clients for the database before calling drop_postgres","Run the drop as a superuser other than the role being dropped","Reassign or DROP OWNED BY the role's objects in all databases first"],"tags":["database","postgres","role-management","cleanup"],"backgroundTag":"database-query-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}