embassy-rs/embassy · error

QSPI data must be at least one byte

Error message

QSPI data must be at least one byte

What it means

A data length of exactly 0 bytes was requested with a data transfer. The QSPI transaction machinery cannot express a zero-length data phase meaningfully, so the library treats it as a configuration mistake and panics.

Solutions

  1. Issue the transaction without a data phase (data_len = None, dwidth = QspiWidth::NONE) for command/address-only operations.
  2. Guard the call: skip or early-return when the buffer is empty.
  3. Fix the length computation so at least one byte is requested when data transfer is intended.

Example fix

// before
if buf.is_empty() { /* still issues transaction */ }
qspi.blocking_read(addr, &mut buf[..0]);
// after
if buf.is_empty() { return Ok(()); } // or send a command-only transaction
qspi.blocking_read(addr, &mut buf);
Defensive patterns

Strategy: validation

Validate before calling

fn data_phase_ok(len: Option<usize>, w: QspiWidth) -> bool {
    match (len, w) {
        (Some(0), _) => false,
        (Some(_), QspiWidth::NONE) => false,
        (None, w) => w == QspiWidth::NONE,
        _ => true,
    }
}

Prevention

When it happens

Trigger: Calling blocking_read/blocking_write (or a transaction routed through setup_transaction) with data_len = Some(0), e.g. an empty write buffer or a computed length of zero.

Common situations: Slicing an empty buffer for a write; a size/len computation that returns 0 (e.g. reading 0 bytes of a register); generic code that forwards buffer.len() without checking for empty buffers.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/qspi/mod.rs:383

    fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) {
        self.assert_transfer_widths(transaction);

        match (transaction.address, transaction.awidth) {
            (Some(_), QspiWidth::NONE) => panic!("QSPI address can't be sent with an address width of NONE"),
            (Some(address), _) => {
                // u32::bit_width was only stabilized in 1.97
                let address_bit_width = u32::BITS - address.leading_zeros();
                if address_bit_width > transaction.address_size.bit_width() as u32 {
                    panic!("QSPI address too large to be represented with the given address size");
                }
            }
            (None, QspiWidth::NONE) => {}
            (None, _) => panic!("QSPI address is not set, so the address width should be NONE"),
        }

        match (data_len, transaction.dwidth) {
            (Some(0), _) => panic!("QSPI data must be at least one byte"),
            (Some(_), QspiWidth::NONE) => panic!("QSPI data can't be sent with a data width of NONE"),
            (Some(_), _) => {}
            (None, QspiWidth::NONE) => {}
            (None, _) => panic!("QSPI data is empty, so the data width should be NONE"),
        }

        T::REGS.fcr().modify(|v| {
            v.set_csmf(true);
            v.set_ctcf(true);
            v.set_ctef(true);
            v.set_ctof(true);
        });

        while T::REGS.sr().read().busy() {}

        if let Some(len) = data_len {
            T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
        }

View on GitHub (pinned to 463a07b963)