embassy-rs/embassy · error

invalid OUT length

Error message

invalid OUT length {}

What it means

calc_out_len encodes an OUT endpoint's buffer size into the 16-bit USBRAM size field; the btable encoding only supports 2–60 bytes (small windows) or 61–1024 bytes (32-byte blocks). Requesting an OUT endpoint buffer outside 2..=1024 has no hardware encoding, so the driver panics at allocation time (via alloc_endpoint).

Solutions

  1. Use a max_packet_size between 2 and 1024 bytes for OUT endpoints (typically 8/16/32/64 for FS)
  2. Clamp requested sizes: size.clamp(2, 1024) before calling alloc_endpoint
  3. For 2048-byte HS needs, switch to a part/driver variant using usbram_32 (usb_host-style path) that supports larger sizes
  4. Check where the size value originates (descriptor parse, config constant) and validate it there

Example fix

// before
let ep_out = dev.alloc_endpoint(EndpointType::Bulk, 0, 64)?; // IN=0 ok, OUT=0 panics if used for OUT
let ep_out = dev.alloc_endpoint(EndpointType::Bulk, 2048, 2048)?; // OUT 2048 panics
// after
let ep_out = dev.alloc_endpoint(EndpointType::Bulk, 64, 64)?; // both within 2..=1024
Defensive patterns

Strategy: validation

Validate before calling

fn out_len_ok(len: u16) -> bool { (2..=1024).contains(&len) }
// before alloc_endpoint: assert!(out_len_ok(out_size));

Type guard

fn valid_out_size(len: u16) -> bool { (2..=1024).contains(&len) }

Prevention

When it happens

Trigger: Calling usb_dev.alloc_endpoint(EndpointType::Bulk/Interrupt/Isochronous, max_packet_size = 0 or 1, or > 1024) on the btable-based usb.rs driver; also 0-byte OUT allocations fall into the wildcard arm.

Common situations: Passing wMaxPacketSize straight from a descriptor that is 0 or misparsed; requesting USB3-era 2048-byte packets on classic btable parts (max 1024); typos like 10 instead of 64 (still fine) vs 1 instead of 10 (panics).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/usb/usb.rs:168

    r.set_ctr_tx(true); // don't clear
    r.set_dtog_rx(false); // don't toggle
    r.set_dtog_tx(false); // don't toggle
    r.set_stat_rx(Stat::from_bits(0));
    r.set_stat_tx(Stat::from_bits(0));
    r
}

fn align_len_up(len: u16) -> u16 {
    ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16
}

// Returns (actual_len, len_bits)
fn calc_out_len(len: u16) -> (u16, u16) {
    match len {
        // NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity.
        2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10),
        61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000),
        _ => panic!("invalid OUT length {}", len),
    }
}

#[cfg(not(any(usbram_32_2048, usbram_32_1024)))]
mod btable {
    use super::*;

    pub(super) fn write_in_tx<T: Instance>(index: usize, addr: u16) {
        USBRAM.mem(index * 4 + 0).write_value(addr);
    }

    pub(super) fn write_in_rx<T: Instance>(index: usize, addr: u16) {
        USBRAM.mem(index * 4 + 2).write_value(addr);
    }

    pub(super) fn write_in_len_rx<T: Instance>(index: usize, _addr: u16, len: u16) {
        USBRAM.mem(index * 4 + 3).write_value(len);
    }

View on GitHub (pinned to 463a07b963)