{"record":{"id":"a16c5e53d87ef05e","repo":"embassy-rs/embassy","slug":"interruptexecutor-spawner-called-on-uninitializ-a16c5e","errorCode":null,"errorMessage":"InterruptExecutor::spawner() called on uninitialized executor.","messagePattern":"InterruptExecutor::spawner\\(\\) called on uninitialized executor\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-rp/src/executor.rs","lineNumber":256,"sourceCode":"            }\n\n            let executor = unsafe { (&*self.executor.get()).assume_init_ref() };\n\n            unsafe { NVIC::unmask(irq) }\n\n            executor.spawner().make_send()\n        }\n\n        /// Get a SendSpawner for this executor\n        ///\n        /// This returns a [`SendSpawner`](embassy_executor::SendSpawner) you can use to spawn tasks on this\n        /// executor.\n        ///\n        /// This MUST only be called on an executor that has already been started.\n        /// The function will panic otherwise.\n        pub fn spawner(&'static self) -> embassy_executor::SendSpawner {\n            if !critical_section::with(|cs| self.started.borrow(cs).get()) {\n                panic!(\"InterruptExecutor::spawner() called on uninitialized executor.\");\n            }\n            let executor = unsafe { (&*self.executor.get()).assume_init_ref() };\n            executor.spawner().make_send()\n        }\n    }\n}\n","sourceCodeStart":238,"sourceCodeEnd":263,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-rp/src/executor.rs#L238-L263","documentation":"`InterruptExecutor::spawner` reads the executor's inner state which is only initialized by `start`; if `start` was never called the MaybeUninit is still uninitialized and dereferencing would be UB, so the driver checks the `started` flag and panics instead.","triggerScenarios":"Calling `EXECUTOR.spawner()` before `EXECUTOR.start(irq)` anywhere in the program, e.g. spawning tasks in a task setup function that runs before the main init sequence.","commonSituations":"Reordering init code so a module's `statics`/task spawner executes before executor start; a spawn path in a library that assumes the executor is already running; race between two init paths where spawner is fetched first.","solutions":["Ensure `InterruptExecutor::start(irq)` is called before any `spawner()` call, ideally as the first step in main/boot","Obtain the `SendSpawner` once after start and pass it down instead of calling `spawner()` ad hoc","If start order is nondeterministic, restructure so spawner acquisition happens in the same function/after start via a channel or OnceCell"],"exampleFix":"// before\nlet spawner = EXECUTOR.spawner(); // start not yet called\nEXECUTOR.start(irqs::Irq0);\n// after\nEXECUTOR.start(irqs::Irq0);\nlet spawner = EXECUTOR.spawner();\n","handlingStrategy":"validation","validationCode":"fn get_spawner_after_start(irq: impl InterruptNumber) -> embassy_executor::SendSpawner {\n    EXECUTOR.start(irq); // if start may double-run, guard it first\n    EXECUTOR.spawner()\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enforce start-before-spawner ordering in one boot function","Cache the SendSpawner from start()/spawner() and pass it to modules","Avoid fetching the spawner from independent init paths"],"tags":["rust","embedded","rp2040","executor","uninitialized","ordering"],"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"}