{"record":{"id":"37bd4249ff41b1d3","repo":"embassy-rs/embassy","slug":"bad-mode","errorCode":null,"errorMessage":"Bad Mode","messagePattern":"Bad Mode","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/can/bxcan/mod.rs","lineNumber":904,"sourceCode":"    /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.\n    pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {\n        self.info.state.lock(|s| match &s.borrow().rx_mode {\n            RxMode::Buffered(_) => {\n                if let Ok(result) = self.rx_buf.try_receive() {\n                    match result {\n                        Ok(envelope) => Ok(envelope),\n                        Err(e) => Err(TryReadError::BusError(e)),\n                    }\n                } else {\n                    if let Some(err) = self.info.regs.curr_error() {\n                        return Err(TryReadError::BusError(err));\n                    } else {\n                        Err(TryReadError::Empty)\n                    }\n                }\n            }\n            _ => {\n                panic!(\"Bad Mode\")\n            }\n        })\n    }\n\n    /// Waits while receive queue is empty.\n    pub async fn wait_not_empty(&mut self) {\n        poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await\n    }\n\n    /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.\n    pub fn reader(&self) -> BufferedCanReceiver {\n        BufferedCanReceiver {\n            rx_buf: self.rx_buf.receiver().into(),\n            info: RxInfoRef::new(&self.info),\n        }\n    }\n\n    /// Accesses the filter banks owned by this CAN peripheral.","sourceCodeStart":886,"sourceCodeEnd":922,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/can/bxcan/mod.rs#L886-L922","documentation":"This panic fires inside the bxCAN receive path when the peripheral's RX mode is neither Buffered nor NonBuffered-with-queue at the point try_read is called — i.e. the RxFifo/TxMode state machine in embassy-stm32's can driver is in an unexpected variant. It indicates internal invariant violation: the receive mode was changed (or torn down) while a read was in flight, which the safe API contract forbids.","triggerScenarios":"Calling try_read (or the blocking read wrapper) on a can::RxFifo/Rx instance while the CAN state's rx_mode is neither Buffered mode nor the mode that try_read expects — typically after reconfiguring splits/modes while receivers are still alive.","commonSituations":"Re-splitting or reconfiguring the CAN peripheral at runtime while an old receiver handle is still used; type-confusion from holding a receiver across a mode change; driver misuse in async tasks that outlive the configuration that created them.","solutions":["Ensure the CAN peripheral's mode/split configuration is fixed for the lifetime of all Receiver handles; drop receivers before reconfiguring","Do not mix buffered and non-buffered receiver usage on the same peripheral; create readers only from the mode you actually configured","Update embassy-stm32 to the latest version, as the bxcan mode state machine has seen refactors; if it persists with valid single-mode usage, file a bug — it is a driver invariant violation, not user error"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Rust: before reading, ensure the CAN peripheral was split/configured exactly once and no reconfigure code path runs while this receiver exists (use a type-state/peripheral-ownership design).","typeGuard":"// Rust: fn is_nonbuffered(rx: &RxMode) -> bool { matches!(rx, RxMode::NonBuffered(_)) } // not directly accessible; enforce by never re-splitting an owned peripheral","tryCatchPattern":"// Rust: panics cannot be caught in no_std embedded code; prevent by design — keep mode configuration immutable for the life of all handles. Use catch_unwind only as a last resort on hosted targets.","preventionTips":["Treat CAN mode configuration as immutable after init","Drop receivers before any reconfiguration","Never mix buffered and non-buffered receive APIs","Keep one owner (single task) for peripheral reconfiguration"],"tags":["embedded","stm32","can","bxcan","panic","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}