tokio-rs/tokio · error · io::Error
signal driver gone
Error message
signal driver gone
What it means
Handle::check_inner for the signal driver returns this io::Error when the inner driver Arc's strong_count is 0, i.e. the signal driver thread/loop has been dropped. Any signal API (signal::ctrl_c, unix::signal) needs the live driver to deliver notifications.
Source
Thrown at tokio/src/runtime/signal/mod.rs:137
Ok(_) => continue, // Keep reading
Err(e) if e.kind() == std_io::ErrorKind::WouldBlock => break,
Err(e) => panic!("Bad read on self-pipe: {e}"),
}
}
// Broadcast any signals which were received
globals().broadcast();
}
}
// ===== impl Handle =====
impl Handle {
pub(crate) fn check_inner(&self) -> std_io::Result<()> {
if self.inner.strong_count() > 0 {
Ok(())
} else {
Err(std_io::Error::new(
std_io::ErrorKind::Other,
"signal driver gone",
))
}
}
}
View on GitHub (pinned to 625954f365)
Solutions
- Build the runtime with enable_all() (or enable_io + enable_signal) so the signal driver runs.
- Keep the runtime alive across the entire span of signal::ctrl_c().await.
- Call signal APIs only from within tokio runtime context.
- Treat 'signal driver gone' as terminal shutdown and exit the process gracefully.
Example fix
// before
let rt = runtime::Builder::new_current_thread().enable_time().build()?;
rt.block_on(async { signal::ctrl_c().await }); // fails: no signal driver
// after
let rt = runtime::Builder::new_current_thread().enable_all().build()?;
rt.block_on(async { signal::ctrl_c().await }); Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the runtime was built with enable_all before relying on signals. // For manual builds: Builder::new_current_thread().enable_all().build()
Try / catch
match signal::ctrl_c().await {
Ok(()) => {},
Err(e) if e.to_string().contains("signal driver gone") => {
// graceful: treat as shutdown
return;
}
Err(e) => return Err(e),
} Prevention
- Use enable_all() so the signal driver runs.
- Keep the runtime alive for the duration of signal::ctrl_c().await.
- Call signal APIs only inside tokio runtime context.
When it happens
Trigger: Calling signal::ctrl_c() or Signal::new() when the runtime was built without a signal driver or the runtime/driver has been dropped; using a current-thread runtime that exited.
Common situations: Building a runtime with only enable_time() (not enable_all); dropping the runtime then awaiting ctrl_c; calling signal APIs from a non-Tokio thread after the runtime ended.
Related errors
- there is no signal driver running, must be called from the c
- background task failed
- background task failed
- A Tokio 1.x context was found, but it is being shutdown.
- A Tokio 1.x context was found, but it is being shutdown.
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/56cdab00ea54fef2.
Report an issue: GitHub.