{"record":{"id":"a6533650a29e27ed","repo":"embassy-rs/embassy","slug":"invalid-channel-config-duplicate-channel","errorCode":null,"errorMessage":"Invalid channel config, duplicate channel {}.","messagePattern":"Invalid channel config, duplicate channel (.+?)\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-usb/src/class/uac1/speaker.rs","lineNumber":146,"sourceCode":"        let control_interface = interface.interface_number();\n        let streaming_interface = u8::from(control_interface) + 1;\n        let mut alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None);\n\n        // Terminal topology:\n        // Input terminal (receives audio stream) -> Feature Unit (mute and volume) -> Output terminal (e.g. towards speaker)\n\n        // =======================================\n        // Input Terminal Descriptor [UAC 3.3.2.1]\n        // Audio input\n        let terminal_type: u16 = TerminalType::UsbStreaming.into();\n\n        // Assemble channel configuration field\n        let mut channel_config: u16 = ChannelConfig::None.into();\n        for channel in channels {\n            let channel: u16 = channel.get_channel_config().into();\n\n            if channel_config & channel != 0 {\n                panic!(\"Invalid channel config, duplicate channel {}.\", channel);\n            }\n            channel_config |= channel;\n        }\n\n        let input_terminal_descriptor = [\n            INPUT_TERMINAL, // bDescriptorSubtype\n            INPUT_UNIT_ID,  // bTerminalID\n            terminal_type as u8,\n            (terminal_type >> 8) as u8, // wTerminalType\n            0x00,                       // bAssocTerminal (none)\n            channels.len() as u8,       // bNrChannels\n            channel_config as u8,\n            (channel_config >> 8) as u8, // wChannelConfig\n            0x00,                        // iChannelNames (none)\n            0x00,                        // iTerminal (none)\n        ];\n\n        // ========================================","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-usb/src/class/uac1/speaker.rs#L128-L164","documentation":"The UAC1 speaker class validates that each requested channel occupies a distinct bit in the 16-bit channel configuration mask. If two channels map to the same configuration bit (a duplicate), the resulting audio descriptor would be ambiguous, so Speaker::new panics naming the duplicated mask value.","triggerScenarios":"Calling Speaker::new with a channel list containing two channels whose get_channel_config() bits overlap — e.g. the same channel repeated, or two variant channels sharing a flag.","commonSituations":"Hand-assembling channel arrays for multi-channel (5.1/7.1) setups; accidentally including a channel twice; custom ChannelConfig impls returning overlapping bits.","solutions":["Remove the duplicate channel from the `channels` slice passed to Speaker::new.","Ensure each channel variant has a unique ChannelConfig bit.","Pre-validate the list with the same mask-and-check logic before constructing the Speaker."],"exampleFix":"// before\nlet channels = &[Channel::FrontLeft, Channel::FrontLeft, Channel::FrontRight];\n// after\nlet channels = &[Channel::FrontLeft, Channel::FrontRight, Channel::FrontCenter];","handlingStrategy":"validation","validationCode":"fn channels_are_unique(channels: &[Channel]) -> bool {\n    let mut mask: u16 = 0;\n    channels.iter().all(|c| {\n        let bit: u16 = c.get_channel_config().into();\n        if mask & bit != 0 { return false; }\n        mask |= bit;\n        true\n    })\n}\nassert!(channels_are_unique(&channels));","typeGuard":"fn channels_are_unique(channels: &[Channel]) -> bool {\n    let mut mask: u16 = 0;\n    channels.iter().all(|c| {\n        let bit: u16 = c.get_channel_config().into();\n        if mask & bit != 0 { return false; }\n        mask |= bit;\n        true\n    })\n}","tryCatchPattern":null,"preventionTips":["Deduplicate the channel list before Speaker::new","Keep one ChannelConfig bit per channel variant","Test descriptor generation for each channel layout you ship"],"tags":["embedded","usb","audio","uac1","config","panic"],"backgroundTag":"invalid-argument-value","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"}