{"record":{"id":"318d61e88e79d643","repo":"embassy-rs/embassy","slug":"you-can-only-call-endpoint-after-interface-inte","errorCode":null,"errorMessage":"you can only call `endpoint` after `interface/interface_alt`.","messagePattern":"you can only call `endpoint` after `interface/interface_alt`\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-usb/src/descriptor.rs","lineNumber":262,"sourceCode":"    /// Writes an endpoint descriptor.\n    ///\n    /// # Arguments\n    ///\n    /// * `endpoint` - Endpoint previously allocated with\n    ///   [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder).\n    /// * `synchronization_type` - The synchronization type of the endpoint.\n    /// * `usage_type` - The usage type of the endpoint.\n    /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor.\n    pub fn endpoint(\n        &mut self,\n        endpoint: &EndpointInfo,\n        synchronization_type: SynchronizationType,\n        usage_type: UsageType,\n        extra_fields: &[u8],\n    ) {\n        match self.num_endpoints_mark {\n            Some(mark) => self.buf[mark] += 1,\n            None => panic!(\"you can only call `endpoint` after `interface/interface_alt`.\"),\n        };\n\n        let mut bm_attributes = endpoint.ep_type as u8;\n\n        // Synchronization types other than `NoSynchronization`,\n        // and usage types other than `DataEndpoint`\n        // are only allowed for isochronous endpoints.\n        if endpoint.ep_type != EndpointType::Isochronous {\n            assert_eq!(synchronization_type, SynchronizationType::NoSynchronization);\n            assert_eq!(usage_type, UsageType::DataEndpoint);\n        } else {\n            if usage_type == UsageType::FeedbackEndpoint {\n                assert_eq!(synchronization_type, SynchronizationType::NoSynchronization)\n            }\n\n            let synchronization_bm_attributes: u8 = (synchronization_type as u8) << 2;\n            let usage_bm_attributes: u8 = (usage_type as u8) << 4;\n","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-usb/src/descriptor.rs#L244-L280","documentation":"The DescriptorWriter tracks the endpoint count of the current interface via a mark set by `interface()`/`interface_alt()`. Calling `endpoint()` when no interface is active leaves the bNumEndpoints counter location unknown, so the writer panics to prevent emitting an invalid USB interface descriptor.","triggerScenarios":"Calling `DescriptorWriter::endpoint()` before any `interface()`/`interface_alt()` call on the writer, or after the interface was closed with `end_interfaces()`.","commonSituations":"Writing endpoints inside `get_string_descriptors` or device-descriptor paths instead of the configuration path; forgetting to open an interface before registering endpoints in a custom class; calling `endpoint` after ending the interface.","solutions":["Call `interface(...)` (or `interface_alt(...)`) before the first `endpoint()` call for that interface.","Move `endpoint()` calls inside the interface block, before `end_interfaces()`.","Verify the code runs in `get_configuration_descriptors`, not another descriptor callback.","Keep endpoint declarations paired 1:1 with interface blocks in custom UsbClass implementations."],"exampleFix":"// before\nfn get_configuration_descriptors(&self, w: &mut DescriptorWriter) {\n    w.endpoint(&ep_cfg)?; // no interface open\n}\n// after\nfn get_configuration_descriptors(&self, w: &mut DescriptorWriter) {\n    w.configuration(1)?;\n    w.interface(0, 0, 1, 0xFF, 0, 0, None)?;\n    w.endpoint(&ep_cfg)?;\n    w.end_interfaces();\n    w.end_configuration();\n    Ok(())\n}","handlingStrategy":"validation","validationCode":"fn get_configuration_descriptors(&self, w: &mut DescriptorWriter) -> Result<(), DescriptorError> {\n    w.configuration(1)?;\n    w.interface(0, 0, 1, 0xFF, 0, 0, None)?; // must precede any endpoint() call\n    w.endpoint(&EP_IN_DESC)?;\n    w.end_interfaces();\n    w.end_configuration();\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call endpoint() before interface()/interface_alt() on the same writer","Count endpoints declared per interface and keep it <= 16 (bNumEndpoints is a nibble)","Emit endpoints only between interface() and end_interfaces()","Mirror the ordering used in embassy-usb example classes"],"tags":["usb","embedded","panic","descriptor-builder"],"backgroundTag":"invalid-state-transition","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"}