{"record":{"id":"bc5615d30066d8d3","repo":"zed-industries/zed","slug":"not-implemented","errorCode":null,"errorMessage":"not implemented","messagePattern":"not implemented","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/project/src/debugger/session.rs","lineNumber":2009,"sourceCode":"        self.set_ignore_breakpoints(!self.ignore_breakpoints, cx)\n    }\n\n    pub(crate) fn set_ignore_breakpoints(\n        &mut self,\n        ignore: bool,\n        cx: &mut App,\n    ) -> Task<HashMap<Arc<Path>, anyhow::Error>> {\n        if self.ignore_breakpoints == ignore {\n            return Task::ready(HashMap::default());\n        }\n\n        self.ignore_breakpoints = ignore;\n\n        if let Some(local) = self.as_running() {\n            local.send_source_breakpoints(ignore, &self.breakpoint_store, cx)\n        } else {\n            // todo(debugger): We need to propagate this change to downstream sessions and send a message to upstream sessions\n            unimplemented!()\n        }\n    }\n\n    pub fn data_breakpoints(&self) -> impl Iterator<Item = &DataBreakpointState> {\n        self.data_breakpoints.values()\n    }\n\n    pub fn exception_breakpoints(\n        &self,\n    ) -> impl Iterator<Item = &(ExceptionBreakpointsFilter, IsEnabled)> {\n        self.exception_breakpoints.values()\n    }\n\n    pub fn toggle_exception_breakpoint(&mut self, id: &str, cx: &App) {\n        if let Some((_, is_enabled)) = self.exception_breakpoints.get_mut(id) {\n            *is_enabled = !*is_enabled;\n            self.send_exception_breakpoints(cx);\n        }","sourceCodeStart":1991,"sourceCodeEnd":2027,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/project/src/debugger/session.rs#L1991-L2027","documentation":"This is Rust's unimplemented!() macro: executing it panics with 'not implemented'. Session::set_ignore_breakpoints only implements propagation for a running local session (as_running() -> local.send_source_breakpoints); for every other state the code deliberately panics, with an adjacent todo acknowledging that propagation to downstream/upstream sessions was never written.","triggerScenarios":"Calling set_ignore_breakpoints(ignore) with a new value while the session has no running local debug adapter — debuggee already terminated, session stopped/deferred before launch, or a remote/attached session — hits the else branch and panics.","commonSituations":"Toggling the breakpoints-enabled switch in the debugger UI right after the debuggee exits or before it starts; a race where the session stops between the ignore flag check and the as_running() call; scripted or extension-driven breakpoint toggles on non-running sessions.","solutions":["As a user: restart the debug session, then toggle ignore-breakpoints again","As a caller: guard the call with the session's running state (as_running().is_some()) and skip when not running","Upstream fix: replace unimplemented!() with Task::ready(HashMap::default()) (flag already stored, synced on next launch) or propagate an Err instead of panicking"],"exampleFix":"// before\nif let Some(local) = self.as_running() {\n    local.send_source_breakpoints(ignore, &self.breakpoint_store, cx)\n} else {\n    unimplemented!()\n}\n\n// after\nif let Some(local) = self.as_running() {\n    local.send_source_breakpoints(ignore, &self.breakpoint_store, cx)\n} else {\n    // Flag is stored; it will be applied when a session next runs.\n    Task::ready(HashMap::default())\n}","handlingStrategy":"type-guard","validationCode":"// Only propagate the flag while a local session is actually running\nlet has_running = session.as_running().is_some();\nif has_running && session.ignore_breakpoints() != ignore {\n    session.set_ignore_breakpoints(ignore, cx);\n}","typeGuard":"fn can_sync_breakpoints(session: &debugger::Session) -> bool {\n    // set_ignore_breakpoints only implements the running-local path;\n    // everything else hits unimplemented!().\n    session.as_running().is_some()\n}","tryCatchPattern":"// Rust: this is a panic, not a Result — catch_unwind only as a last resort\nuse std::panic::{catch_unwind, AssertUnwindSafe};\nlet outcome = catch_unwind(AssertUnwindSafe(|| {\n    session.set_ignore_breakpoints(ignore, cx)\n}));\nif outcome.is_err() {\n    log::error!(\"set_ignore_breakpoints panicked; session not running?\");\n}","preventionTips":["Never call state-mutating debugger APIs on sessions you have not verified are running","Gate UI toggles on the debugger's running state and disable them otherwise","Upstream: replace unimplemented!() with a no-op task or an Err — a todo comment is not a crash guard"],"tags":["rust","debugger","panic","breakpoints","zed"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}