embassy-rs/embassy · error

unrecognized rx error

Error message

unrecognized rx error

What it means

On RP2040/RP2350 UART, embassy-rp maps the UART's RX error interrupts (break, parity, framing) to Error variants in `read()`. If the error interrupt fired but none of `beis`, `peis`, `feis` are set, the driver cannot classify the error and panics with `unreachable!`, indicating an unhandled hardware state.

Solutions

  1. Update embassy-rp; newer versions may classify additional RX error sources (e.g. overrun).
  2. Clear pending UART error interrupts (via `uartris`/`uarticr`) before re-attempting reads.
  3. Check whether another task/isr shares the same UART and causes races; serialize access.
  4. If reproducible, capture the `uartris` register value and report it upstream as a driver bug.
Defensive patterns

Strategy: try-catch

Try / catch

// Rust panics cannot be caught on-device; handle recoverable errors via Result:
match uart.read(&mut buf) {
    Ok(n) => { /* ... */ }
    Err(Error::Framing) => log::warn!("framing error"),
    Err(Error::Parity) => log::warn!("parity error"),
    Err(e) => log::error!("uart error: {:?}", e),
}

Prevention

When it happens

Trigger: A `read()` call encounters a UART error interrupt where `peris()`, `feris()`, and the break flag are all clear, so the flag chain falls through to `unreachable!`.

Common situations: Overrun conditions or noise-triggered interrupts not mapped by this driver version; concurrent access to the UART causing a stale/spurious error interrupt; hardware revisions raising additional RX error sources.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/256791bbe43b434a. Report an issue: GitHub.

Appendix: source

Thrown at embassy-rp/src/uart/mod.rs:552

            }
        };

        // If we got no error, just return at this point
        if errors.0 == 0 {
            return Ok(());
        }

        // If we DID get an error, we need to figure out which one it was.
        if errors.oeris() {
            return Err(Error::Overrun);
        } else if errors.beris() {
            return Err(Error::Break);
        } else if errors.peris() {
            return Err(Error::Parity);
        } else if errors.feris() {
            return Err(Error::Framing);
        }
        unreachable!("unrecognized rx error");
    }

    /// Read from the UART, waiting for a break.
    ///
    /// We read until one of the following occurs:
    ///
    /// * We read `buffer.len()` bytes without a break
    ///     * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
    /// * We read `n` bytes then a break occurs
    ///     * returns `Ok(n)`
    /// * We encounter some error OTHER than a break
    ///     * returns `Err(ReadToBreakError::Other(error))`
    ///
    /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
    /// message to reliably detect the framing on one single call to `read_to_break()`.
    ///
    /// * If you expect a message of 20 bytes + break, and provide a 20-byte buffer:
    ///     * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`

View on GitHub (pinned to 463a07b963)