{"record":{"id":"c2283bc520feee73","repo":"embassy-rs/embassy","slug":"invalid-out-length-c2283b","errorCode":null,"errorMessage":"invalid OUT length {}","messagePattern":"invalid OUT length (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/usb/usb_host.rs","lineNumber":173,"sourceCode":"    r.set_stat_tx(Stat::from_bits(0));\n    r\n}\n\nfn align_len_up(len: u16) -> u16 {\n    ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16\n}\n\n/// Calculates the register field values for configuring receive buffer descriptor.\n/// Returns `(actual_len, len_bits)`\n///\n/// `actual_len` length in bytes rounded up to USBRAM_ALIGN\n/// `len_bits` should be placed on the upper 16 bits of the register value\nfn calc_receive_len_bits(len: u16) -> (u16, u16) {\n    match len {\n        // NOTE: this could be 1..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity.\n        1..=60 => (align_len_up(len), align_len_up(len) / 2 << 10),\n        61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000),\n        _ => panic!(\"invalid OUT length {}\", len),\n    }\n}\n\n#[cfg(any(usbram_32_2048, usbram_32_1024))]\nmod btable {\n    use super::*;\n\n    pub(super) fn write_in<I: Instance>(_index: usize, _addr: u16) {}\n\n    /// Writes to Transmit Buffer Descriptor for Channel/endpoint `index``\n    /// For Device this is an IN endpoint for Host an OUT endpoint\n    pub(super) fn write_transmit_buffer_descriptor<I: Instance>(index: usize, addr: u16, len: u16) {\n        // Address offset: index*8 [bytes] thus index*2 in 32 bit words\n        USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));\n    }\n\n    /// Writes to Receive Buffer Descriptor for Channel/endpoint `index``\n    /// For Device this is an OUT endpoint for Host an IN endpoint","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/usb/usb_host.rs#L155-L191","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nhost.alloc_pipe(EndpointType::Bulk, addr, ep, dir, 2048, interval)?; // >1024 panics\n// after\nhost.alloc_pipe(EndpointType::Bulk, addr, ep, dir, 512, interval)?; // legal on 32-bit usbram\n// or clamp\nlet len = requested_len.clamp(1, 1024);","handlingStrategy":"validation","validationCode":"fn rx_len_ok(len: u16) -> bool { (1..=1024).contains(&len) }\n// before alloc_pipe/restore_control_channel: assert!(rx_len_ok(rx_size));","typeGuard":"fn valid_pipe_rx_size(len: u16) -> bool { (1..=1024).contains(&len) }","tryCatchPattern":null,"preventionTips":["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"],"tags":["embedded","stm32","usb","host","endpoint","panic"],"backgroundTag":"value-out-of-range","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}