embassy-rs/embassy · error
invalid OUT length
Error message
invalid OUT length {} What it means
calc_receive_len_bits (usb_host.rs) encodes a pipe's OUT receive buffer size into USBRAM register bits; valid encodings cover 1–60 bytes and 61–1024 bytes. A pipe buffer length outside that range (0 or >1024) has no hardware representation, so the driver panics when restore_control_channel or alloc_pipe sets up the pipe.
Solutions
- Use receive (OUT) pipe buffer sizes within 1..=1024 bytes (64 is the FS standard)
- Clamp: let len = len.clamp(1, 1024); before pipe allocation
- For >1024-byte transfers, rely on multi-packet transfers rather than enlarging a single pipe buffer
- Audit where the size constant comes from (descriptor or config) and validate at that boundary
Example fix
// before host.alloc_pipe(EndpointType::Bulk, addr, ep, dir, 2048, interval)?; // >1024 panics // after host.alloc_pipe(EndpointType::Bulk, addr, ep, dir, 512, interval)?; // legal on 32-bit usbram // or clamp let len = requested_len.clamp(1, 1024);
Defensive patterns
Strategy: validation
Validate before calling
fn rx_len_ok(len: u16) -> bool { (1..=1024).contains(&len) }
// before alloc_pipe/restore_control_channel: assert!(rx_len_ok(rx_size)); Type guard
fn valid_pipe_rx_size(len: u16) -> bool { (1..=1024).contains(&len) } Prevention
- Clamp receive pipe sizes to 1..=1024
- Never pass 0 as an OUT/receive pipe buffer size
- Handle large transfers with multi-packet logic rather than oversized single buffers
- Validate host config constants at startup, before pipe setup
When it happens
Trigger: UsbHost alloc_pipe / restore_control_channel calls with an OUT (receive) max_packet_size of 0 or greater than 1024 on btable-based USBRAM parts.
Common situations: Host stacks copied from device code where packet size 0 means 'unused'; requesting high-speed 2048-byte receive buffers on full-speed btable parts; misreading direction and passing an IN size of 0 into the OUT pipe setup.
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
- invalid OUT length
- Endpoint memory full
- USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but…
- USB clock should be 48Mhz but is
- USB HS PHY reference clock should be 19.2, 20 or 24 MHz but…
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/c2283bc520feee73.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/usb/usb_host.rs:173
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
}
/// Calculates the register field values for configuring receive buffer descriptor.
/// Returns `(actual_len, len_bits)`
///
/// `actual_len` length in bytes rounded up to USBRAM_ALIGN
/// `len_bits` should be placed on the upper 16 bits of the register value
fn calc_receive_len_bits(len: u16) -> (u16, u16) {
match len {
// NOTE: this could be 1..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity.
1..=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(any(usbram_32_2048, usbram_32_1024))]
mod btable {
use super::*;
pub(super) fn write_in<I: Instance>(_index: usize, _addr: u16) {}
/// Writes to Transmit Buffer Descriptor for Channel/endpoint `index``
/// For Device this is an IN endpoint for Host an OUT endpoint
pub(super) fn write_transmit_buffer_descriptor<I: Instance>(index: usize, addr: u16, len: u16) {
// Address offset: index*8 [bytes] thus index*2 in 32 bit words
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
}
/// Writes to Receive Buffer Descriptor for Channel/endpoint `index``
/// For Device this is an OUT endpoint for Host an IN endpointView on GitHub (pinned to 463a07b963)