loco-rs/loco · error

create DB schema

Error message

create DB schema

What it means

After connecting as root, `init_db` issues `CREATE DATABASE {schema_name};`. If that SQL fails — the database already exists, insufficient privileges, invalid identifier, or the server rejects concurrent creation — `.expect("create DB schema")` panics inside the test-support initializer.

Solutions

  1. Re-run with a clean DB state or drop leftovers: `psql -U postgres -c 'DROP DATABASE IF EXISTS loco_test_x;'`
  2. Ensure each test process/worker uses a unique schema name (unique suffix per PID) to avoid parallel collisions
  3. Grant the test root CREATEDB: `ALTER USER test_user CREATEDB;` or run tests against a local superuser Postgres
  4. Use `createdb`-capable local Postgres in CI rather than managed instances with restricted privileges

Example fix

// before
$ cargo test  # panics: database "loco_test_abc" already exists
// after
$ psql -U postgres -c 'DROP DATABASE IF EXISTS loco_test_abc;'
$ cargo test
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the user can create databases and no leftover DB exists
// psql -U postgres -c "SELECT rolcreatedb FROM pg_roles WHERE rolname='test_user';"
// psql -U postgres -c "DROP DATABASE IF EXISTS loco_test_tmp;"

Prevention

When it happens

Trigger: Running tests with parallel test binaries that pick the same schema name (database already exists), a root user lacking CREATEDB, or a schema name with characters requiring quoting.

Common situations: Two test crates sharing the same `--test-threads` DB name in one CI job; leftover DB from a previous crashed run; managed Postgres (e.g. RDS/Cloud SQL) where the test user is not a superuser and cannot CREATE DATABASE.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/38cdd8becd7a2c47. Report an issue: GitHub.

Appendix: source

Thrown at src/testing/db.rs:127

    }
}

impl TestSupport for PostgresTest {
    fn get_connection_str(&self) -> &str {
        &self.connection_string
    }

    fn init_db<'a>(&'a self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
        Box::pin(async move {
            let pool = Pool::<Postgres>::connect(&self.root_connection_string)
                .await
                .expect("db connection should success");
            let query = format!("CREATE DATABASE {};", self.schema_name);

            sqlx::query(AssertSqlSafe(query))
                .execute(&pool)
                .await
                .expect("create DB schema");
        })
    }

    fn cleanup_db(&self) {
        let connection_string = self.root_connection_string.clone();
        let table_name = self.schema_name.clone();

        // Run the drop on a dedicated OS thread with its own runtime (not
        // `tokio::task::spawn_blocking`, which schedules onto the ambient
        // runtime and cannot be awaited from a sync/Drop context) and `.join()`
        // it so cleanup fully completes before `cleanup_db` returns. This is
        // safe to call from `Drop::drop` since nothing here is `.await`ed on
        // the caller's runtime.
        std::thread::spawn(move || {
            let rt = tokio::runtime::Runtime::new().expect("create cleanup runtime");

            rt.block_on(async {
                let pool = Pool::<Postgres>::connect(&connection_string)

View on GitHub (pinned to 23639d1e36)