tokio-rs/tokio · critical
A Tokio 1.x context was found, but timers are disabled. Call
Error message
A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.
What it means
Driver::time() calls .expect(...) when self.time is None — the runtime was built without the time driver (no enable_time / not enable_all), yet code uses tokio::time APIs (sleep, interval, timeout).
Source
Thrown at tokio/src/runtime/driver.rs:115
cfg_signal_internal_and_unix! {
#[track_caller]
pub(crate) fn signal(&self) -> &crate::runtime::signal::Handle {
self.signal
.as_ref()
.expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
}
}
cfg_time! {
/// Returns a reference to the time driver handle.
///
/// Panics if no time driver is present.
#[track_caller]
pub(crate) fn time(&self) -> &crate::runtime::time::Handle {
self.time
.as_ref()
.expect("A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.")
}
#[cfg(tokio_unstable)]
pub(crate) fn with_time<F, R>(&self, f: F) -> R
where
F: FnOnce(Option<&crate::runtime::time::Handle>) -> R,
{
f(self.time.as_ref())
}
pub(crate) fn clock(&self) -> &Clock {
&self.clock
}
}
}
// ===== io driver =====
View on GitHub (pinned to 7d0d729d8f)
Solutions
- Call .enable_all() (or .enable_time()) on the Builder.
- Don't call tokio::time::* on time-disabled runtimes; route timer usage to a full runtime.
- Audit Builder config and ensure enable_time when timers are used.
- If you truly need no timers, eliminate all sleep/timeout/interval usages in that runtime's scope.
Example fix
// before
let rt = Builder::new_current_thread().enable_io().build()?;
rt.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await; }); // panics
// after
let rt = Builder::new_current_thread().enable_all().build()?;
rt.block_on(async { tokio::time::sleep(Duration::from_secs(1)).await; }); Defensive patterns
Strategy: validation
Validate before calling
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all() // ensures time driver is on
.build()?; Try / catch
// Macro panics; manual build surfaces error:
match Builder::new_current_thread().enable_all().build() {
Ok(rt) => rt.block_on(async { tokio::time::sleep(...).await }),
Err(e) => { eprintln!("no time driver: {e}"); std::process::exit(1); }
} Prevention
- Call enable_all() (or enable_time()) on the Builder.
- Never use tokio::time::* on a time-disabled runtime.
- Audit Builder configs when isolating compute workloads.
When it happens
Trigger: Calling sleep/interval/timeout on a runtime whose Builder lacks enable_time(); using a minimal Builder for compute then awaiting a timer.
Common situations: Custom Builder omitting enable_all; intentionally disabling timers then accidentally calling sleep; test harness with stripped-down runtime.
Related errors
- there is no signal driver running, must be called from the c
- A Tokio 1.x context was found, but IO is disabled. Call `ena
- provided length would overflow after adjustment
- background task failed
- background task failed
AI-assisted analysis of tokio-rs/tokio@7d0d729d8f (2026-08-11).
Data as JSON: /api/errors/0dd6cfb940685261.
Report an issue: GitHub.