rust-embedded/rust-raspberrypi-OS-tutorials · error

Error handling IRQ

Error message

Error handling IRQ

What it means

After finding a registered IRQ descriptor, the GICv2 driver calls descriptor.handler().handle() and expects Ok(()); if the handler itself reports failure, the .expect("Error handling IRQ") panics. This library throws it because an IRQ handler that cannot service its interrupt leaves the peripheral in a stuck state and the error must be surfaced loudly.

Source

Thrown at 20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs:212

        &'irq_context self,
        ic: &exception::asynchronous::IRQContext<'irq_context>,
    ) {
        // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register
        // (IAR).
        let irq_number = self.gicc.pending_irq_number(ic);

        // Guard against spurious interrupts.
        if irq_number > GICv2::MAX_IRQ_NUMBER {
            return;
        }

        // Call the IRQ handler. Panic if there is none.
        self.handler_table.read(|table| {
            match table[irq_number] {
                None => panic!("No handler registered for IRQ {}", irq_number),
                Some(descriptor) => {
                    // Call the IRQ handler. Panics on failure.
                    descriptor.handler().handle().expect("Error handling IRQ");
                }
            }
        });

        // Signal completion of handling.
        self.gicc.mark_comleted(irq_number as u32, ic);
    }

    fn print_handler(&self) {
        use crate::info;

        info!("      Peripheral handler:");

        self.handler_table.read(|table| {
            for (i, opt) in table.iter().skip(32).enumerate() {
                if let Some(handler) = opt {
                    info!("            {: >3}. {}", i + 32, handler.name());
                }

View on GitHub (pinned to 644474cc09)

Solutions

  1. Inspect the failing handler's handle() implementation and its error type to see which internal condition failed.
  2. Fix the handler so it correctly acknowledges/clears the interrupt source in the peripheral's status registers.
  3. Verify device initialization order — the handler's device must be fully initialized before its IRQ is enabled.
  4. If handle() returns Err for spurious interrupts, make the handler tolerate them (return Ok for no-op firings) instead of erroring.

Example fix

// before
fn handle(&self) -> Result<(), &'static str> {
    Err("unexpected interrupt") // propagates -> expect("Error handling IRQ") panic
}
// after
fn handle(&self) -> Result<(), &'static str> {
    self.clear_status();
    Ok(())
}
Defensive patterns

Strategy: validation

Validate before calling

// Handlers must be able to service their IRQ; verify the source is pending before enabling:
assert!(timer.status_pending_bit_is_accessible(), "timer IRQ source must be serviceable");

Prevention

When it happens

Trigger: A registered IRQ handler's handle() implementation returns Err — e.g. the timer handler cannot clear its match/status register, a device's status register read fails the handler's internal validity checks, or the handler's expected state does not match reality when the IRQ fires.

Common situations: Timer handler called but timer registers were reconfigured concurrently, handler written for a different device revision whose status bits differ, IRQ shared/raced so the handler finds nothing to service and errors out, or a handler whose internal invariants were violated by earlier init mistakes.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/0fdaa64e19047b56. Report an issue: GitHub.