rust-embedded/rust-raspberrypi-OS-tutorials · error
transition_to_single_core_main() called while state != Init
Error message
transition_to_single_core_main() called while state != Init
What it means
transition_to_single_core_main() performs an atomic compare_exchange from INIT to SINGLE_CORE_MAIN; if the exchange fails the current state was not INIT, so the kernel panics. This enforces a one-way, exactly-once state transition: the kernel may enter single-core-main mode only once, from the init state. Calling it twice, or after another transition, triggers this panic.
Source
Thrown at 20_timer_callbacks/kernel/src/state.rs:89
/// Return if the kernel is init state.
pub fn is_init(&self) -> bool {
self.state() == State::Init
}
/// Transition from Init to SingleCoreMain.
pub fn transition_to_single_core_main(&self) {
if self
.0
.compare_exchange(
Self::INIT,
Self::SINGLE_CORE_MAIN,
Ordering::Acquire,
Ordering::Relaxed,
)
.is_err()
{
panic!("transition_to_single_core_main() called while state != Init");
}
}
}
View on GitHub (pinned to 644474cc09)
Solutions
- Call the transition exactly once, from a single designated boot path/core.
- Guard the call: check `state() == State::Init` (or use is_init()) before attempting the transition, and skip if already transitioned.
- If multiple cores race, elect one main core (core id check) before calling.
- If re-init is genuinely needed, reset the state atom back to INIT first (only where safe/designed).
Example fix
// before
kernel_state.transition_to_single_core_main();
// after
if kernel_state.is_init() {
kernel_state.transition_to_single_core_main();
} Defensive patterns
Strategy: validation
Validate before calling
fn can_transition_to_single_core_main(current: State) -> bool {
current == State::Init
} Type guard
fn is_init_state(raw: u8) -> bool {
raw == INIT
} Try / catch
// The transition panics on failure; check first:
if kernel_state.is_init() {
kernel_state.transition_to_single_core_main();
} else {
log::warn!("skipping transition, already initialized");
} Prevention
- Call state transitions from exactly one boot path/core.
- Use is_init() as a precondition check before any transition.
- Elect a single main core before boot-time transitions.
- Do not attempt re-initialization of an already-initialized kernel.
When it happens
Trigger: Calling transition_to_single_core_main() twice (e.g. re-running boot logic, a second CPU entering the same path); calling it after transition_to_multi_core_main(); calling it on an already-initialized kernel in a restart/re-init attempt.
Common situations: Boot code executed on multiple cores racing to transition (only the INIT->SINGLE_CORE_MAIN winner succeeds); a test harness or reboot path re-invoking init routines; duplicate initialization of the kernel driver; state already advanced by a prior subsystem init.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Invalid KERNEL_STATE
- Error initializing timer subsystem: {}
- Overflow on Address::sub
- Allocation error: {:?}
- Attempt to enable IRQ {} for device {}, but driver does not
AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06).
Data as JSON: /api/errors/b17100820379643e.
Report an issue: GitHub.