embassy-rs/embassy · error
InterruptExecutor::start() called multiple times on the…
Error message
InterruptExecutor::start() called multiple times on the same executor.
What it means
Panic raised by the aarch32 InterruptExecutor::start implementation's internal state guard. Each interrupt executor can be started exactly once: start() writes the raw executor state into the static slot and enables the software-generated interrupt. A second call would overwrite partially-initialized state and re-arm the SGI, corrupting the running executor. This fires when application or platform init code calls start() on the same 'static executor instance twice, typically from duplicated board-init paths or a restarted module.
Solutions
- Call InterruptExecutor::start() exactly once per executor instance, at a single well-known init point
- Guard the start call with an application-level 'initialized' flag or OnceCell so repeated init paths are idempotent
- If restart is required, create a new static executor instance instead of re-starting the existing one
- Audit board startup code so the executor is not started from both main and a secondary-core or reset path
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at embassy-executor/src/platform/aarch32.rs:269 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/05c15a014868f7d1.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-executor/src/platform/aarch32.rs:269
/// You must set the interrupt priority (in `GICD_IPRIORITYR`) before calling this method.
/// You MUST NOT do it after.
///
/// The SGI may be configured as either Group 0 or Group 1 in `GICD_IGROUPR0`. You must
/// configure the group before calling this method, you MUST NOT change it after.
///
/// The SGI is always sent to the CPU that pends it, so on multi-core chips the executor
/// must only be woken from the core it was started on.
///
/// # Panics
///
/// Panics if `sgi_id` is greater than 15, or if the executor was already started.
///
/// [`SendSpawner`]: crate::SendSpawner
pub fn start(&'static self, gicd_base: usize, sgi_id: u8) -> crate::SendSpawner {
assert!(sgi_id < 16, "SGI interrupt ID must be in the range 0..=15");
if critical_section::with(|cs| self.started.borrow(cs).replace(true)) {
panic!("InterruptExecutor::start() called multiple times on the same executor.");
}
let inner = unsafe {
let inner = (*self.inner.get()).as_mut_ptr();
// Initialize the target first: the executor's pender context points to it.
(&raw mut (*inner).target).write(SgiTarget::new(gicd_base, sgi_id));
let target = &raw const (*inner).target;
(&raw mut (*inner).executor).write(raw::Executor::new(target as *mut ()));
&*inner
};
inner.target.enable();
inner.executor.spawner().make_send()
}
/// Get a SendSpawner for this executor
///View on GitHub (pinned to 463a07b963)