{"record":{"id":"92b121825de92e4b","repo":"rwf2/Rocket","slug":"timedout","errorCode":"TimedOut","errorMessage":"shutdown grace period elapsed","messagePattern":"shutdown grace period elapsed","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"core/lib/src/listener/cancellable.rs","lineNumber":46,"sourceCode":"    Grace,\n    /// Grace has elapsed. Shutdown connections. After `Shutdown`, force close.\n    Mercy,\n}\n\npub trait CancellableExt: Sized {\n    fn cancellable(self, stages: Stages) -> Cancellable<Self> {\n        Cancellable {\n            io: Some(self),\n            state: State::Active,\n            stages,\n        }\n    }\n}\n\nimpl<T> CancellableExt for T { }\n\nfn time_out() -> io::Error {\n    io::Error::new(io::ErrorKind::TimedOut, \"shutdown grace period elapsed\")\n}\n\nfn gone() -> io::Error {\n    io::Error::new(io::ErrorKind::BrokenPipe, \"I/O driver terminated\")\n}\n\nimpl<I: AsyncCancel> Cancellable<I> {\n    pub fn inner(&self) -> Option<&I> {\n        self.io.as_ref()\n    }\n}\n\npub trait AsyncCancel {\n    fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;\n}\n\nimpl<T: AsyncWrite> AsyncCancel for T {\n    fn poll_cancel(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/rwf2/Rocket/blob/3a54d079aef060a8f732bd04ea54b0581a604087/core/lib/src/listener/cancellable.rs#L28-L64","documentation":"Internal runtime error from Rocket's shutdown machinery (core/lib/src/listener/cancellable.rs): during graceful shutdown, each connection is given the configured grace period to finish; when it elapses with I/O still pending, the cancellable I/O wrapper returns io::ErrorKind::TimedOut with message 'shutdown grace period elapsed'. It signals forced termination of a still-active connection at shutdown, not a request-handling failure.","triggerScenarios":"Rocket shutdown begins (SIGTERM/Ctrl-C, config.shutdown), a client keeps a connection open or a slow request is mid-flight, and shutdown.grace (default 5s) expires before that I/O completes. Subsequent read/write polls on that connection yield this error.","commonSituations":"Container orchestration sending SIGTERM while long uploads/downloads run; SSE/WebSocket-style long-lived connections still open at shutdown; slow mobile clients mid-request during a rolling deploy.","solutions":["Increase the grace period in Rocket.toml: [default.shutdown] grace = 30","Notify clients to disconnect before shutdown (e.g. close websockets in a shutdown fairing) so connections drain faster","Pair a long grace with an orchestrator-level terminationGracePeriodSeconds larger than Rocket's grace","Treat the error as expected during shutdown logging — filter it instead of alerting"],"exampleFix":"# before\n# Rocket.toml (defaults: grace = 5s)\n\n# after\n# Rocket.toml\n[default.shutdown]\ngrace = 30\n# also raise k8s: terminationGracePeriodSeconds: 40","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// in connection-handling code, treat TimedOut at shutdown as expected\nmatch stream.read(&mut buf).await {\n    Err(e) if e.kind() == io::ErrorKind::TimedOut\n        && e.to_string().contains(\"grace period\") => { /* shutting down: bail quietly */ break; }\n    r => { /* normal handling */ }\n}","preventionTips":["Size shutdown.grace to your slowest legitimate request, not to 5s defaults","Send clients a signal (Connection: close, websocket close frame) before initiating shutdown","Keep orchestrator termination grace above Rocket's grace so SIGKILL never cuts it short"],"tags":["rust","rocket","shutdown","graceful-shutdown","runtime"],"backgroundTag":"graceful-shutdown-timeout","analyzedSha":"3a54d079aef060a8f732bd04ea54b0581a604087","analyzedAt":"2026-08-16T22:01:48.395Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}