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

  1. 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.
  2. 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).
  3. 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.
  4. Verify the migration files are embedded/sorted correctly (`migrations/*.sql` naming order matters) and that the target dialect supports the SQL used.
  5. 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

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


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/906913101871b05e. Report an issue: GitHub.