tokio-rs/tokio · error · io::Error
A Tokio 1.x context was found, but it is being shutdown.
Error message
A Tokio 1.x context was found, but it is being shutdown.
What it means
Registration::gone() returns this io::Error when an I/O resource operation is attempted against an I/O driver that has been shut down. It indicates the ScheduledIo/Registration backing a socket/file is no longer connected to a live driver, so async I/O cannot proceed.
Source
Thrown at tokio/src/runtime/io/registration.rs:255
self.handle.driver().io()
}
}
impl Drop for Registration {
fn drop(&mut self) {
// It is possible for a cycle to be created between wakers stored in
// `ScheduledIo` instances and `Arc<driver::Inner>`. To break this
// cycle, wakers are cleared. This is an imperfect solution as it is
// possible to store a `Registration` in a waker. In this case, the
// cycle would remain.
//
// See tokio-rs/tokio#3481 for more details.
self.shared.clear_wakers();
}
}
fn gone() -> io::Error {
io::Error::new(
io::ErrorKind::Other,
crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR,
)
}
View on GitHub (pinned to 625954f365)
Solutions
- Keep the runtime alive for the entire lifetime of any owned I/O resource.
- Close/drop sockets before dropping the runtime.
- Detect shutdown via the returned error and propagate it instead of retrying.
- Avoid capturing I/O resources in long-lived 'static spawns tied to a shorter-lived runtime.
Example fix
// before
let stream = TcpStream::connect(...).await?;
drop(runtime);
stream.read_buf(&mut buf).await?; // returns gone()
// after
let n = stream.read_buf(&mut buf).await;
match n {
Err(e) if e.to_string().contains("shutting down") => return,
_ => {},
} Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure resource lifetime <= runtime lifetime by design; no cheap runtime check exists. // Optionally: assert the runtime guard is held in your API entry points.
Try / catch
match resource.read_buf(&mut buf).await {
Ok(_) => {},
Err(e) if e.to_string().contains("shutting down") => {
// driver gone: clean up and exit
return;
}
Err(e) => return Err(e),
} Prevention
- Drop all I/O resources before dropping the runtime.
- Never move sockets into 'static tasks tied to a shorter-lived runtime.
- Structure shutdown ordering: close sockets, then drop runtime.
When it happens
Trigger: Using an async TcpStream/UdpStream/UnixStream after its runtime's I/O driver has shut down; registering or reading/writing on a resource whose driver Arc has gone away.
Common situations: Holding an I/O handle past runtime drop; moving a TcpStream into a 'static task that outlives the runtime; test harnesses that drop the runtime while connections linger.
Related errors
- A Tokio 1.x context was found, but it is being shutdown.
- background task failed
- background task failed
- signal driver gone
- blocking pool shutting down
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/6ffff9cf35025b67.
Report an issue: GitHub.