loco-rs/loco · error
create cleanup runtime
Error message
create cleanup runtime
What it means
`cleanup_db` runs DB teardown from a synchronous context (including `Drop`) by spawning a dedicated OS thread that builds a fresh tokio `Runtime`. `Runtime::new()` failing — e.g. the process is out of resources or a runtime limitation is hit — panics with 'create cleanup runtime', aborting cleanup and typically surfacing during test teardown.
Solutions
- Reduce test parallelism (`--test-threads`) or the number of concurrently live test DBs so fewer cleanup threads/runtimes exist
- Raise container/thread limits (`ulimit -u`, more memory in CI)
- Prefer explicit async cleanup (call teardown inside the test's runtime) over relying on sync Drop-based cleanup
- Check tokio feature flags are the standard ones; do not globally disable rt features in dependency overrides
Defensive patterns
Strategy: fallback
Validate before calling
// Sanity-check headroom for spawning the cleanup runtime
let max_threads = std::fs::read_to_string("/proc/sys/kernel/threads-max")
.ok().and_then(|s| s.trim().parse::<i64>().ok());
println!("threads-max = {:?}", max_threads); // low values risk Runtime::new failure Try / catch
// Prefer explicit async cleanup inside the test runtime over Drop-based sync cleanup // async test body: // test_support.cleanup().await; // instead of relying on Drop
Prevention
- Limit test parallelism when creating many test DBs
- Do explicit async cleanup instead of relying on Drop
- Give CI containers enough memory/thread limits
- Keep tokio features standard (rt-multi-thread)
When it happens
Trigger: Calling cleanup when the process cannot allocate a new tokio runtime (thread/resource exhaustion, `set_current_thread` runtime builder misconfiguration via env, extremely constrained containers).
Common situations: Huge parallel test suites hitting thread limits; container memory limits killing runtime bootstrap; exotic runtimes where tokio cannot spawn its blocking pool.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- failed to install signal handler
- db cleanup thread panicked
- failed to install Ctrl+C handler
- logger initialization failed
- fs service should build with success
AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12).
Data as JSON: /api/errors/5a6d2e9c81bf609f.
Report an issue: GitHub.
Appendix: source
Thrown at src/testing/db.rs:142
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)
.await
.expect("db connection should success");
let query = format!("drop database if exists {table_name};");
sqlx::query(AssertSqlSafe(query))
.execute(&pool)
.await
.expect("Drop database");
});
})
.join()
.expect("db cleanup thread panicked");
}
}
pub struct SqliteTest {View on GitHub (pinned to 23639d1e36)