transact-rs/sqlx · error
failed to apply migrations
Error message
failed to apply migrations
What it means
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.
Source
Thrown at sqlx-core/src/testing/mod.rs:262
}
async fn setup_test_db<DB: Database>(
copts: &<DB::Connection as Connection>::Options,
args: &TestArgs,
) where
DB::Connection: Migrate + Sized,
for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,
{
let mut conn = copts
.connect()
.await
.expect("failed to connect to test database");
if let Some(migrator) = args.migrator {
migrator
.run_direct(None, &mut conn, false)
.await
.expect("failed to apply migrations");
}
for fixture in args.fixtures {
(&mut conn)
.execute(fixture.contents)
.await
.unwrap_or_else(|e| panic!("failed to apply test fixture {:?}: {:?}", fixture.path, e));
}
conn.close()
.await
.expect("failed to close setup connection");
}
View on GitHub (pinned to 03af8bcc57)
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.
Example fix
// before: editing an already-applied migration // migrations/0001_init.sql <- modified after being applied => checksum/SQL failure in tests // after: leave 0001_init.sql untouched; add // migrations/0002_add_users_email.sql ALTER TABLE users ADD COLUMN email TEXT;
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: run migrations against a scratch DB before #[sqlx::test]
async fn migrations_apply_cleanly(migrator: &Migrator, url: &str) -> Result<(), sqlx::Error> {
let pool = sqlx::AnyPool::connect(url).await?;
let mut conn = pool.acquire().await?;
migrator.run_direct(None, &mut conn, false).await?;
Ok(())
} Type guard
// no dynamic type to narrow; guard the invariant instead:
// a migration file once applied must never be edited (checksum check)
fn migration_was_modified(applied_checksum: &str, file_checksum: &str) -> bool {
applied_checksum != file_checksum
} Try / catch
// #[sqlx::test] panics on failure; capture the cause in CI
let result = std::panic::catch_unwind(|| {
tokio::runtime::Handle::current().block_on(setup_test_db(args))
});
if let Err(panic) = result {
let msg = panic.downcast_ref::<String>().map(String::as_str)
.unwrap_or("setup_test_db panicked");
eprintln!("test DB setup failed: {msg} — inspect the wrapped run_direct error above");
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: `#[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.
Related errors
- failed to apply test fixture {:?}: {:?}
- unimplemented!()
- expected to read {} bytes, got {} bytes at EOF
- Hostname did not resolve to any addresses
- Unix domain sockets are not supported on this platform
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/906913101871b05e.
Report an issue: GitHub.