{"record":{"id":"278e98de4ab4cdcf","repo":"embassy-rs/embassy","slug":"can-only-take-the-executor-once","errorCode":null,"errorMessage":"Can only take the executor once","messagePattern":"Can only take the executor once","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"embassy-mcxa/src/executor.rs","lineNumber":68,"sourceCode":"\n        let context = context as usize;\n\n        // Try to make Rust optimize the branching away if we only use thread mode.\n        if context == THREAD_PENDER {\n            TASKS_PENDING.store(true, Ordering::Release);\n            cortex_m::asm::sev();\n        }\n    }\n}\n\nimpl Executor {\n    // Note: We don't really want a Default impl for this singleton.\n    #[allow(clippy::new_without_default)]\n    pub fn new() -> Self {\n        let res = EXECUTOR_ONCE.compare_exchange(EXECUTOR_UNINIT, EXECUTOR_TAKEN, Ordering::AcqRel, Ordering::Relaxed);\n\n        if res.is_err() {\n            panic!(\"Can only take the executor once\");\n        }\n\n        Self {\n            inner: raw::Executor::new(THREAD_PENDER as *mut ()),\n            not_send: PhantomData,\n        }\n    }\n\n    /// Run the executor.\n    ///\n    /// The `init` closure is called with a [`Spawner`] that spawns tasks on\n    /// this executor. Use it to spawn the initial task(s). After `init` returns,\n    /// the executor starts running the tasks.\n    ///\n    /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),\n    /// for example by passing it as an argument to the initial tasks.\n    ///\n    /// This function requires `&'static mut self`. This means you have to store the","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-mcxa/src/executor.rs#L50-L86","documentation":"This panic fires when `Executor::new()` is called more than once in a program. The executor is a process-wide singleton guarded by the EXECUTOR_ONCE atomic (compare_exchange UNINIT -> TAKEN); a second call fails the CAS and panics, because two executors would compete for the same thread pender and interrupt state. Rust panics abort/embedded programs cannot be caught, so this is a hard programming error.","triggerScenarios":"Calling `Executor::new()` twice, e.g. once in main and once in a helper/spawned task, or calling it again after an earlier init path (like a board-support init function) already created it.","commonSituations":"Copy-pasting executor setup from examples into a second module; refactoring startup code so two call sites both construct the executor; accidentally linking two crates that each create an embassy executor for the same core.","solutions":["Find and remove the duplicate `Executor::new()` call so exactly one exists per core/thread.","Create the executor once in `main` and pass `&'static` references (via `Executor::new()` + `static` or `SingletonToken`-style sharing) to other modules instead of re-creating it.","If two independent task domains are needed, use separate executor mechanisms designed for that (e.g. interrupt executor or a second core's executor), not two calls on the same core."],"exampleFix":"// before\nstatic EXEC: Executor = Executor::new();\nfn setup() { let ex2 = Executor::new(); } // panics\n// after\nstatic EXEC: Executor = Executor::new();\nfn setup() { /* use &EXEC, never call Executor::new() again */ }","handlingStrategy":"validation","validationCode":"// Call Executor::new() exactly once; keep it in a single static:\nstatic EXECUTOR: StaticCell<Executor> = StaticCell::new();\nlet executor: &'static mut Executor = EXECUTOR.init(Executor::new());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call Executor::new() outside of main/startup; search codebase for all call sites before adding one.","Store the executor in a static and share &'static references instead of re-constructing.","Keep executor creation in one dedicated init module or BSP function."],"tags":["embedded","rust","panic","executor","singleton"],"backgroundTag":"internal-invariant-violation","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"}