{"record":{"id":"795ca544ffb7d0e3","repo":"embassy-rs/embassy","slug":"if-composite-with-iads-is-set-you-must-set-device","errorCode":null,"errorMessage":"if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01","messagePattern":"if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-usb/src/builder.rs","lineNumber":197,"sourceCode":"impl<'d, D: Driver<'d>> Builder<'d, D> {\n    /// Creates a builder for constructing a new [`UsbDevice`].\n    ///\n    /// `control_buf` is a buffer used for USB control request data. It should be sized\n    /// large enough for the length of the largest control request (in or out)\n    /// anticipated by any class added to the device.\n    pub fn new(\n        driver: D,\n        config: Config<'d>,\n        config_descriptor_buf: &'d mut [u8],\n        bos_descriptor_buf: &'d mut [u8],\n        msos_descriptor_buf: &'d mut [u8],\n        control_buf: &'d mut [u8],\n    ) -> Self {\n        // Magic values specified in USB-IF ECN on IADs.\n        if config.composite_with_iads\n            && (config.device_class != 0xEF || config.device_sub_class != 0x02 || config.device_protocol != 0x01)\n        {\n            panic!(\n                \"if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01\"\n            );\n        }\n\n        assert!(\n            config.max_power <= 500,\n            \"The maximum allowed value for `max_power` is 500mA\"\n        );\n\n        match config.max_packet_size_0 {\n            8 | 16 | 32 | 64 => {}\n            _ => panic!(\"invalid max_packet_size_0, the allowed values are 8, 16, 32 or 64\"),\n        }\n\n        let mut config_descriptor = DescriptorWriter::new(config_descriptor_buf);\n        let mut bos_descriptor = BosWriter::new(DescriptorWriter::new(bos_descriptor_buf));\n\n        config_descriptor.configuration(&config);","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-usb/src/builder.rs#L179-L215","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nlet config = Config { composite_with_iads: true, device_class: 0x00, device_sub_class: 0x00, device_protocol: 0x00, .. };\n// after\nlet config = Config { composite_with_iads: true, device_class: 0xEF, device_sub_class: 0x02, device_protocol: 0x01, .. };","handlingStrategy":"validation","validationCode":"fn check_composite(cfg: &Config) -> bool {\n    !cfg.composite_with_iads\n        || (cfg.device_class == 0xEF && cfg.device_sub_class == 0x02 && cfg.device_protocol == 0x01)\n}\nassert!(check_composite(&config));","typeGuard":"fn check_composite(cfg: &Config) -> bool {\n    !cfg.composite_with_iads\n        || (cfg.device_class == 0xEF && cfg.device_sub_class == 0x02 && cfg.device_protocol == 0x01)\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["embedded","usb","config","panic"],"backgroundTag":"conflicting-config-options","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"}