transact-rs/sqlx · critical
this functionality requires a Tokio context
Error message
this functionality requires a Tokio context
What it means
missing_rt() in sqlx-core/src/rt/mod.rs is sqlx's guard for runtime-abstract APIs. When the `_rt-tokio` feature IS enabled but the API is called outside any active Tokio runtime/context, sqlx panics with 'this functionality requires a Tokio context' (the second panic branch, 'one of the runtime features...' only fires when no runtime feature is compiled in). Many sqlx operations (pool creation, queries, timers) spawn on the async runtime and cannot run without one.
Source
Thrown at sqlx-core/src/rt/mod.rs:166
cfg_if! {
if #[cfg(feature = "_rt-async-io")] {
async_io::block_on(f)
} else if #[cfg(feature = "_rt-tokio")] {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("failed to start Tokio runtime")
.block_on(f)
} else {
missing_rt(f)
}
}
}
#[track_caller]
pub const fn missing_rt<T>(_unused: T) -> ! {
if cfg!(feature = "_rt-tokio") {
panic!("this functionality requires a Tokio context")
}
panic!("one of the `runtime` features of SQLx must be enabled")
}
impl<T: Send + 'static> Future for JoinHandle<T> {
type Output = T;
#[track_caller]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match &mut *self {
#[cfg(feature = "_rt-async-std")]
Self::AsyncStd(handle) => Pin::new(handle).poll(cx),
#[cfg(feature = "_rt-async-task")]
Self::AsyncTask(task) => Pin::new(task)
.as_pin_mut()
.expect("BUG: task taken")View on GitHub (pinned to 03af8bcc57)
Solutions
- Wrap the entry point in a Tokio runtime: `#[tokio::main] async fn main()` or build one manually with `tokio::runtime::Runtime::new()?.block_on(...)`.
- Annotate async tests with `#[tokio::test]` instead of `#[test]`.
- If calling from sync code, use `SomePool::connect_lazy` plus a runtime-owned handle, or move DB work onto a Tokio worker via `runtime.spawn(...)`.
- If your app uses a non-Tokio runtime, switch the sqlx feature to a matching one — but note current sqlx effectively requires Tokio for runtime-dependent APIs.
Example fix
// before
fn main() {
let pool = PgPool::connect("postgres://..."); // panic: no Tokio context
}
// after
#[tokio::main]
async fn main() {
let pool = PgPool::connect("postgres://...").await.unwrap();
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure a Tokio context exists before DB work:
assert!(
tokio::runtime::Handle::try_current().is_ok(),
"sqlx calls require a Tokio runtime context"
); Prevention
- Use #[tokio::main] and #[tokio::test] on every entry point and async test
- Never call async sqlx APIs from sync code without block_on
- Keep DB access behind async functions that are only awaited within the runtime
When it happens
Trigger: Calling `PgPool::connect`, `Pool::acquire`, `query.fetch...` etc. from code not running inside `#[tokio::main]`/`tokio::runtime::Runtime::block_on` — e.g. from a synchronous main, a blocking thread, a C FFI callback, or tests without the `#[tokio::test]` attribute.
Common situations: Rust binaries with plain `fn main()` calling sqlx directly; integration tests missing tokio attributes; embedding sqlx in a non-Tokio app (async-std, smol) while only the tokio feature is enabled.
Related errors
- one of the `runtime` features of SQLx must be enabled
- Cannot use both flatten and json
- Cannot use both try from and json nullable
- one of the `runtime-*-native-tls` or `runtime-*-rustls` feat
- downcast to wrong DatabaseError type; original error: {self}
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/f1f7d2d675a65aeb.
Report an issue: GitHub.