{"record":{"id":"d6e9979538f81f71","repo":"leptos-rs/leptos","slug":"tried-to-access-a-reactive-value-that-has-already","errorCode":null,"errorMessage":"Tried to access a reactive value that has already been disposed.","messagePattern":"Tried to access a reactive value that has already been disposed\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"reactive_graph/src/traits.rs","lineNumber":75,"sourceCode":"};\nuse any_spawner::Executor;\nuse futures::{Stream, StreamExt};\nuse std::{\n    ops::{Deref, DerefMut},\n    panic::Location,\n};\n\n#[doc(hidden)]\n/// Provides a sensible panic message for accessing disposed signals.\n#[macro_export]\nmacro_rules! unwrap_signal {\n    ($signal:ident) => {{\n        #[cfg(any(debug_assertions, leptos_debuginfo))]\n        let location = std::panic::Location::caller();\n        || {\n            #[cfg(any(debug_assertions, leptos_debuginfo))]\n            {\n                panic!(\n                    \"{}\",\n                    $crate::traits::panic_getting_disposed_signal(\n                        $signal.defined_at(),\n                        location\n                    )\n                );\n            }\n            #[cfg(not(any(debug_assertions, leptos_debuginfo)))]\n            {\n                panic!(\n                    \"Tried to access a reactive value that has already been \\\n                     disposed.\"\n                );\n            }\n        }\n    }};\n}\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/reactive_graph/src/traits.rs#L57-L93","documentation":"Accessing a disposed reactive value (signal/memo) in debug builds panics with the definition and access locations. When a reactive owner is disposed (component unmounted or owner dropped), its signals' storage is freed; reading them afterwards is a use-after-free bug in the reactive graph. This is the debug-assertions branch of the disposed-signal panic macro, which includes source locations in the message.","triggerScenarios":"Reading a signal/memo through a closure created by the disposed-signal macro after its owner was disposed — e.g. an async task or timeout callback holding a ReadSignal whose component has unmounted, or an event listener on a node that outlives the signal's scope.","commonSituations":"setTimeout/setInterval or async fetch resolving after the component unmounted and then set_* / read the signal; storing signals in a global or long-lived struct instead of in the owning scope; manual ownership via Owner::new without keeping the scope alive; hydration/SSR teardown reading client signals.","solutions":["Keep the owning scope alive as long as the value is needed: move signal creation up to a longer-lived owner or use a global store.","Cancel or guard async work: check ownership before reading (use Owner::with or a generation flag) so callbacks after dispose do nothing.","Use spawn_local within the component scope and abort/drop pending tasks on cleanup (on_cleanup).","For data that must outlive components, put it in a global reactive store or context rather than a local signal."],"exampleFix":"// before\nlet (count, set_count) = create_signal(0);\nsetTimeout(move || set_count.set(1), 5000); // may fire after dispose\n\n// after\nlet (count, set_count) = create_signal(0);\non_cleanup(move || handle.clear_timeout()); // or guard reads with ownership check\nsetTimeout(move || set_count.set(1), 5000);","handlingStrategy":"try-catch","validationCode":"// before storing/reading: ensure the owner is alive\nif scope_is_active() { set_count.set(new_value); }","typeGuard":"fn signal_alive<T>(s: &ReadSignal<T>) -> bool { !s.try_get().is_none() } // heuristic; prefer ownership checks","tryCatchPattern":"std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| signal.get())).unwrap_or(default_value)","preventionTips":["Cancel timers/fetches in on_cleanup when they touch component-local signals.","Use spawn_local, not tokio::spawn, for reactive-scope tasks.","Move long-lived state out of component scopes into stores/context."],"tags":["leptos","reactive-graph","disposed-signal","use-after-dispose","panic"],"backgroundTag":"access-disposed-reactive-value","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}