{"record":{"id":"af6dd487676da2a6","repo":"rust-embedded/rust-raspberrypi-OS-tutorials","slug":"no-handler-registered-for-irq-af6dd4","errorCode":null,"errorMessage":"No handler registered for IRQ {}","messagePattern":"No handler registered for IRQ (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs","lineNumber":155,"sourceCode":"                &regs.ENABLE_2\n            };\n\n            let enable_bit: u32 = 1 << (irq.get() % 32);\n\n            // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable\n            // bits are unaffected. So we don't need read and OR'ing here.\n            enable_reg.set(enable_bit);\n        });\n    }\n\n    fn handle_pending_irqs<'irq_context>(\n        &'irq_context self,\n        _ic: &exception::asynchronous::IRQContext<'irq_context>,\n    ) {\n        self.handler_table.read(|table| {\n            for irq_number in self.pending_irqs() {\n                match table[irq_number] {\n                    None => panic!(\"No handler registered for IRQ {}\", irq_number),\n                    Some(descriptor) => {\n                        // Call the IRQ handler. Panics on failure.\n                        descriptor.handler().handle().expect(\"Error handling IRQ\");\n                    }\n                }\n            }\n        })\n    }\n\n    fn print_handler(&self) {\n        use crate::info;\n\n        info!(\"      Peripheral handler:\");\n\n        self.handler_table.read(|table| {\n            for (i, opt) in table.iter().enumerate() {\n                if let Some(handler) = opt {\n                    info!(\"            {: >3}. {}\", i, handler.name());","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials/blob/644474cc09f755249f9c55d99a5d1e07a2562fc7/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs#L137-L173","documentation":"The BCM peripheral interrupt controller's handle_pending_irqs walks all pending peripheral IRQs and panics if any has no entry in the handler table. This library throws it because an unclaimed pending peripheral interrupt cannot be dispatched or acknowledged and would otherwise re-trigger indefinitely.","triggerScenarios":"A peripheral IRQ (GPIO, UART, system timer, etc.) becomes pending in the peripheral IC's pending registers while its handler-table slot is None — i.e. the IRQ was unmasked/enabled but register_handler() was never called for it.","commonSituations":"Enabling a system-timer or GPIO IRQ before registering its handler, using GIC-style IRQ numbers instead of BCM peripheral IRQ numbers, enabling IRQs in device drivers during bring-up but deferring handler registration, or a leftover enabled IRQ from a previous boot stage.","solutions":["Register a handler for the printed IRQ number before enabling it in the peripheral interrupt controller.","Disable/mask that IRQ at the controller if it is not supposed to fire.","Map the IRQ number to its device using the BCM datasheet and confirm the numbering scheme matches the controller in use (peripheral vs local vs GIC).","Audit driver init order: register all handlers, then enable IRQs as the last step."],"exampleFix":"// before\nperipheral_ic.irq_manager.enable(irq_number); // IRQ unmasked with no handler\n// after\nperipheral_ic.irq_manager.register_handler(irq_number, &system_timer_handler);\nperipheral_ic.irq_manager.enable(irq_number);","handlingStrategy":"validation","validationCode":"// Enable an IRQ only after its handler is registered:\nfn enable_irq_safely(irq: usize, mgr: &mut IrqManager) {\n    assert!(mgr.handler_registered(irq), \"register a handler before enabling IRQ\");\n    mgr.enable(irq);\n}","typeGuard":"fn handler_slot_filled(irq: usize, table: &[Option<IrqDescriptor>]) -> bool {\n    table.get(irq).map_or(false, |s| s.is_some())\n}","tryCatchPattern":null,"preventionTips":["Treat handler registration as step 1 and IRQ enabling as the final init step in every driver.","Keep separate, documented IRQ-number tables for peripheral vs local controllers on BCM SoCs.","Clear stale enabled IRQs from previous boot stages at controller init.","Provoke each IRQ during testing to confirm it dispatches to a registered handler."],"tags":["interrupts","bcm","raspberry-pi","bare-metal","panic"],"backgroundTag":"missing-irq-handler","analyzedSha":"644474cc09f755249f9c55d99a5d1e07a2562fc7","analyzedAt":"2026-09-06T09:25:56.584Z","contentChangedAt":"2026-09-06T09:25:56.584Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}