{"record":{"id":"0566817f8fb3265d","repo":"tokio-rs/tokio","slug":"cannot-enter-a-task-local-scope-during-or-after-de","errorCode":null,"errorMessage":"cannot enter a task-local scope during or after destruction of the underlying thread-local","messagePattern":"cannot enter a task-local scope during or after destruction of the underlying thread-local","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"tokio/src/task/task_local.rs","lineNumber":473,"sourceCode":"impl fmt::Display for AccessError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(\"task-local value not set\", f)\n    }\n}\n\nimpl Error for AccessError {}\n\nenum ScopeInnerErr {\n    BorrowError,\n    AccessError,\n}\n\nimpl ScopeInnerErr {\n    #[track_caller]\n    fn panic(&self) -> ! {\n        match self {\n            Self::BorrowError => panic!(\"cannot enter a task-local scope while the task-local storage is borrowed\"),\n            Self::AccessError => panic!(\"cannot enter a task-local scope during or after destruction of the underlying thread-local\"),\n        }\n    }\n}\n\nimpl From<std::cell::BorrowMutError> for ScopeInnerErr {\n    fn from(_: std::cell::BorrowMutError) -> Self {\n        Self::BorrowError\n    }\n}\n\nimpl From<std::thread::AccessError> for ScopeInnerErr {\n    fn from(_: std::thread::AccessError) -> Self {\n        Self::AccessError\n    }\n}\n","sourceCodeStart":455,"sourceCodeEnd":489,"githubUrl":"https://github.com/tokio-rs/tokio/blob/625954f365727668cb02d04172b34f1149637728/tokio/src/task/task_local.rs#L455-L489","documentation":"Task-local values are stored in thread-local storage. `scope_inner` first probes the thread-local with `self.inner.try_with(...)` (task_local.rs:209); if the thread-local is mid-destruction or already destroyed, std returns `std::thread::AccessError`, converted to `ScopeInnerErr::AccessError` and panicked at line 473. Entering a task-local scope is only valid while the backing thread-local still exists.","triggerScenarios":"Calling `sync_scope`/`scope` from a `Drop` implementation that runs during thread-local teardown, or after the owning worker thread / runtime has already begun shutting down and its TLS slot is gone.","commonSituations":"Custom smart pointers or guards whose `Drop` touches a task-local while the runtime worker thread is exiting; resources whose destructors observe a task-local during process teardown; background threads spawned outside the runtime that outlive it.","solutions":["Never access or enter task-locals from `Drop` impls that may execute during thread/TLS shutdown.","Make sure all tasks and their resources are fully dropped before the `Runtime` is dropped and its worker threads exit.","Capture any task-local state you need at shutdown into owned data before the runtime is dropped.","If you must probe safely, use `try_with` / `try_with_value` (returning `AccessError`) instead of the panicking `with` / `scope` variants."],"exampleFix":"// before — Drop touches a task-local during teardown\nimpl Drop for Guard {\n    fn drop(&mut self) { VALUE.with(|v| { /* ... */ }); } // may panic at shutdown\n}\n\n// after — fail-soft probe that tolerates a destroyed TLS\nimpl Drop for Guard {\n    fn drop(&mut self) {\n        let _ = VALUE.try_with(|v| { /* ... */ });\n    }\n}","handlingStrategy":"validation","validationCode":"// Use the fallible variant in any context that may run during teardown.\nlet _ = VALUE.try_with(|v| { /* ... */ }); // returns Err(AccessError) instead of panicking","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(|| {\n    VALUE.sync_scope(x, || { /* ... */ })\n}).ok();","preventionTips":["Avoid touching task-locals in `Drop` impls that may execute during thread-local teardown.","Drop/cancel all tasks before dropping the `Runtime`.","Prefer `try_with`/`try_with_value` (which return `Result`, not panic) in any destructor-adjacent code path.","Test shutdown paths explicitly (e.g. `drop(runtime)` with live tasks) under a debugger."],"tags":["tokio","task-local","runtime-panic","thread-local","destructor"],"backgroundTag":null,"analyzedSha":"625954f365727668cb02d04172b34f1149637728","analyzedAt":"2026-08-11T17:46:45.378Z","contentChangedAt":"2026-08-11T17:46:45.378Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}