tokio-rs/tokio · critical
there is no signal driver running, must be called from the c
Error message
there is no signal driver running, must be called from the context of Tokio runtime
What it means
Driver::signal() calls .expect(...) when self.signal is None — the runtime has no signal driver. Signal APIs (ctrl_c, unix::signal) require the signal driver, which is only enabled with enable_all or on platforms with cfg_signal_internal_and_unix.
Source
Thrown at tokio/src/runtime/driver.rs:103
self.io.unpark();
}
cfg_io_driver! {
#[track_caller]
pub(crate) fn io(&self) -> &crate::runtime::io::Handle {
self.io
.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_signal_internal_and_unix! {
#[track_caller]
pub(crate) fn signal(&self) -> &crate::runtime::signal::Handle {
self.signal
.as_ref()
.expect("there is no signal driver running, must be called from the context of Tokio runtime")
}
}
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,View on GitHub (pinned to 625954f365)
Solutions
- Use .enable_all() on the Builder so the signal driver is created.
- On non-Unix/non-supported targets, avoid signal APIs and handle shutdown differently.
- Ensure signal calls originate from within the runtime context (enter()/block_on).
- Verify cfg_signal_internal_and_unix is active for your target.
Example fix
// before
let rt = Builder::new_current_thread().build()?;
rt.block_on(async { signal::ctrl_c().await }); // panics
// after
let rt = Builder::new_current_thread().enable_all().build()?;
rt.block_on(async { signal::ctrl_c().await }); Defensive patterns
Strategy: validation
Validate before calling
// Ensure the signal driver is present by enabling all drivers:
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all() // includes signal driver on Unix
.build()?; Try / catch
// Panic in macro path; manual build lets you handle:
match Builder::new_current_thread().enable_all().build() {
Ok(rt) => rt.block_on(async { signal::ctrl_c().await }),
Err(e) => { eprintln!("no signal driver: {e}"); std::process::exit(1); }
} Prevention
- Use enable_all() so the signal driver runs.
- Confirm cfg_signal_internal_and_unix for your target.
- Call signal APIs only within runtime context.
When it happens
Trigger: Calling signal APIs on a runtime built without enable_io (the signal driver depends on the I/O driver) or on a platform/configuration where cfg_signal_internal_and_unix is off.
Common situations: Builder with only enable_time(); calling ctrl_c from a manually-built current-thread runtime that skipped enable_all; target without Unix signal support.
Related errors
- A Tokio 1.x context was found, but IO is disabled. Call `ena
- A Tokio 1.x context was found, but timers are disabled. Call
- signal driver gone
- provided length would overflow after adjustment
- background task failed
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/f79ac3d49107bd63.
Report an issue: GitHub.