embassy-rs/embassy · error
if composite_with_iads is set, you must set device_class =…
Error message
if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01
What it means
When composite_with_iads is enabled, the USB-IF IAD ECN mandates magic device-level class codes: device_class=0xEF, device_sub_class=0x02, device_protocol=0x01. embassy-usb's Builder::new panics if composite_with_iads is set with any other device class triple, since the resulting descriptor would be non-compliant.
Solutions
- Set device_class: 0xEF, device_sub_class: 0x02, device_protocol: 0x01 whenever composite_with_iads is true.
- If you don't need IADs, set composite_with_iads to false and keep your per-interface classes.
- Centralize the config construction so the IAD flag and class codes are set together.
Example fix
// before
let config = Config { composite_with_iads: true, device_class: 0x00, device_sub_class: 0x00, device_protocol: 0x00, .. };
// after
let config = Config { composite_with_iads: true, device_class: 0xEF, device_sub_class: 0x02, device_protocol: 0x01, .. }; Defensive patterns
Strategy: validation
Validate before calling
fn check_composite(cfg: &Config) -> bool {
!cfg.composite_with_iads
|| (cfg.device_class == 0xEF && cfg.device_sub_class == 0x02 && cfg.device_protocol == 0x01)
}
assert!(check_composite(&config)); Type guard
fn check_composite(cfg: &Config) -> bool {
!cfg.composite_with_iads
|| (cfg.device_class == 0xEF && cfg.device_sub_class == 0x02 && cfg.device_protocol == 0x01)
} Prevention
- Set the IAD magic class codes together with the flag
- Build Config from a helper that keeps related fields consistent
- Only enable composite_with_iads when multiple interface classes need IADs
When it happens
Trigger: Calling Builder::new with Config { composite_with_iads: true, .. } while device_class/device_sub_class/device_protocol keep vendor-specific defaults (e.g. 0x00/0x00/0x00 or 0xFF/0x00/0x00).
Common situations: Enabling IAD-based composite mode (needed for CDC + other interfaces) but forgetting to update the three device descriptor fields; upgrading embassy-usb where this became a hard panic instead of silent misbehavior.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Unsupported EP0 size
- invalid max_packet_size_0, the allowed values are 8, 16, 32…
- Invalid channel config, duplicate channel
- AHB frequency is too low
- USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but…
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/795ca544ffb7d0e3.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-usb/src/builder.rs:197
impl<'d, D: Driver<'d>> Builder<'d, D> {
/// Creates a builder for constructing a new [`UsbDevice`].
///
/// `control_buf` is a buffer used for USB control request data. It should be sized
/// large enough for the length of the largest control request (in or out)
/// anticipated by any class added to the device.
pub fn new(
driver: D,
config: Config<'d>,
config_descriptor_buf: &'d mut [u8],
bos_descriptor_buf: &'d mut [u8],
msos_descriptor_buf: &'d mut [u8],
control_buf: &'d mut [u8],
) -> Self {
// Magic values specified in USB-IF ECN on IADs.
if config.composite_with_iads
&& (config.device_class != 0xEF || config.device_sub_class != 0x02 || config.device_protocol != 0x01)
{
panic!(
"if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01"
);
}
assert!(
config.max_power <= 500,
"The maximum allowed value for `max_power` is 500mA"
);
match config.max_packet_size_0 {
8 | 16 | 32 | 64 => {}
_ => panic!("invalid max_packet_size_0, the allowed values are 8, 16, 32 or 64"),
}
let mut config_descriptor = DescriptorWriter::new(config_descriptor_buf);
let mut bos_descriptor = BosWriter::new(DescriptorWriter::new(bos_descriptor_buf));
config_descriptor.configuration(&config);View on GitHub (pinned to 463a07b963)