{"record":{"id":"906913101871b05e","repo":"transact-rs/sqlx","slug":"failed-to-apply-migrations","errorCode":null,"errorMessage":"failed to apply migrations","messagePattern":"failed to apply migrations","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx-core/src/testing/mod.rs","lineNumber":262,"sourceCode":"}\n\nasync fn setup_test_db<DB: Database>(\n    copts: &<DB::Connection as Connection>::Options,\n    args: &TestArgs,\n) where\n    DB::Connection: Migrate + Sized,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n{\n    let mut conn = copts\n        .connect()\n        .await\n        .expect(\"failed to connect to test database\");\n\n    if let Some(migrator) = args.migrator {\n        migrator\n            .run_direct(None, &mut conn, false)\n            .await\n            .expect(\"failed to apply migrations\");\n    }\n\n    for fixture in args.fixtures {\n        (&mut conn)\n            .execute(fixture.contents)\n            .await\n            .unwrap_or_else(|e| panic!(\"failed to apply test fixture {:?}: {:?}\", fixture.path, e));\n    }\n\n    conn.close()\n        .await\n        .expect(\"failed to close setup connection\");\n}\n","sourceCodeStart":244,"sourceCodeEnd":276,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-core/src/testing/mod.rs#L244-L276","documentation":"In sqlx's test-helper module, `setup_test_db` runs the provided `Migrator` against a freshly created test database via `run_direct(None, ...)` and unwraps with `.expect(\"failed to apply migrations\")`. If any migration fails (SQL error, checksum conflict, already-applied divergent migration), the helper panics instead of returning a `Result`, aborting the test with this message as the panic payload.","triggerScenarios":"Calling `sqlx::testing::setup_test_db` (directly or via the `#[sqlx::test]` attribute with a `migrator` argument) where `migrator.run_direct` returns `Err`: a migration contains invalid SQL for the target DB, a migration is missing from the `_sqlx_migrations` bookkeeping, checksums mismatch, or the DB user lacks DDL privileges.","commonSituations":"`#[sqlx::test(migrations = \"...\")]` tests failing after editing an already-applied migration file, switching test databases between Postgres/MySQL/SQLite with dialect-specific SQL, running tests against a shared database with leftover migration state, or CI using a DB user without CREATE/ALTER rights.","solutions":["Read the wrapped panic cause in the test output — the underlying `run_direct` error names the failing migration file and SQL error; fix that migration's SQL or state.","If you edited an already-applied migration, create a new migration instead of modifying the old one (checksum mismatch), or reset the test database (`DROP DATABASE` / point `DATABASE_URL` at a fresh DB).","Run migrations manually (`sqlx migrate run` or the migrator in a binary) against the same DB to reproduce and see the full error outside the test harness.","Verify the migration files are embedded/sorted correctly (`migrations/*.sql` naming order matters) and that the target dialect supports the SQL used.","If the environment is at fault, grant the test user DDL permissions or use a per-test ephemeral database."],"exampleFix":"// before: editing an already-applied migration\n// migrations/0001_init.sql  <- modified after being applied => checksum/SQL failure in tests\n\n// after: leave 0001_init.sql untouched; add\n// migrations/0002_add_users_email.sql\nALTER TABLE users ADD COLUMN email TEXT;","handlingStrategy":"try-catch","validationCode":"// pre-flight: run migrations against a scratch DB before #[sqlx::test]\nasync fn migrations_apply_cleanly(migrator: &Migrator, url: &str) -> Result<(), sqlx::Error> {\n    let pool = sqlx::AnyPool::connect(url).await?;\n    let mut conn = pool.acquire().await?;\n    migrator.run_direct(None, &mut conn, false).await?;\n    Ok(())\n}","typeGuard":"// no dynamic type to narrow; guard the invariant instead:\n// a migration file once applied must never be edited (checksum check)\nfn migration_was_modified(applied_checksum: &str, file_checksum: &str) -> bool {\n    applied_checksum != file_checksum\n}","tryCatchPattern":"// #[sqlx::test] panics on failure; capture the cause in CI\nlet result = std::panic::catch_unwind(|| {\n    tokio::runtime::Handle::current().block_on(setup_test_db(args))\n});\nif let Err(panic) = result {\n    let msg = panic.downcast_ref::<String>().map(String::as_str)\n        .unwrap_or(\"setup_test_db panicked\");\n    eprintln!(\"test DB setup failed: {msg} — inspect the wrapped run_direct error above\");\n}","preventionTips":["Never edit migrations after they have been applied; always add a new numbered migration.","Run `sqlx migrate run` locally against a fresh DB before pushing tests.","Keep migrations dialect-neutral or per-dialect directories when testing multiple backends.","Ensure the CI database user has DDL privileges (CREATE/ALTER/DROP).","Use per-test ephemeral databases so leftover `_sqlx_migrations` state cannot leak between runs."],"tags":["rust","sqlx","migrations","testing","database"],"backgroundTag":"migration-failed","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"}