embassy-rs/embassy · error

Waker not present for GPIO pin

Error message

Waker not present for GPIO pin {}, port {}

What it means

Panic in InputFuture::poll: after verifying the port's waker slot exists, the code indexes into it with the pin number and finds no waker registered for that specific pin. The per-pin waker is what the GPIO interrupt handler wakes when the configured edge occurs; without it, awaiting the pin's edge would hang forever. This indicates the InputFuture is polling a pin whose interrupt configuration was never registered — typically a pin used before its interrupt was enabled, or a stale future for a pin that was reconfigured or torn down.

Solutions

  1. Enable/configure the pin interrupt for this specific pin before awaiting edges on it
  2. Keep the Input (and its future) alive only while its interrupt configuration is active; re-create the future after reconfiguring the pin
  3. Don't tear down or re-register the pin's interrupt config while an InputFuture is polling it
  4. Trace with the pin and port numbers in the message which pin was misconfigured and fix its setup call
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at embassy-imxrt/src/gpio.rs:456 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/fcf195d256b29d90. Report an issue: GitHub.

Appendix: source

Thrown at embassy-imxrt/src/gpio.rs:456

impl Future for InputFuture<'_> {
    type Output = ();

    fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // We need to register/re-register the waker for each poll because any
        // calls to wake will deregister the waker.
        if self.pin.port() >= GPIO_WAKERS.len() {
            panic!("Invalid GPIO port index {}", self.pin.port());
        }

        let port_waker = GPIO_WAKERS[self.pin.port()];
        if port_waker.is_none() {
            panic!("Waker not present for GPIO port {}", self.pin.port());
        }

        let waker = port_waker.unwrap().get_waker(self.pin.pin());
        if waker.is_none() {
            panic!(
                "Waker not present for GPIO pin {}, port {}",
                self.pin.pin(),
                self.pin.port()
            );
        }
        waker.unwrap().register(cx.waker());

        // Double check that the pin interrut has been disabled by IRQ handler
        if self.pin.block().intena(self.pin.port()).read().bits() & (1 << self.pin.pin()) == 0 {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}

/// Output pin
/// Cannot be set as an input and cannot read its own pin state!

View on GitHub (pinned to 463a07b963)