{"record":{"id":"e5cc888a095a91c8","repo":"embassy-rs/embassy","slug":"invalid-filterconfig-toomanyfilters-a-filtercon","errorCode":null,"errorMessage":"Invalid FilterConfig (TooManyFilters)! A FilterConfig must adhere to the constraint `2*(num_extended) + (num_standard) <= 32`.","messagePattern":"Invalid FilterConfig \\(TooManyFilters\\)! A FilterConfig must adhere to the constraint `2\\*\\(num_extended\\) \\+ \\(num_standard\\) <= 32`\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-mcxa/src/flexcan/filter.rs","lineNumber":116,"sourceCode":"\n    /// Number of extended filters.\n    pub(crate) num_extended: usize,\n}\n\nimpl<'a> FilterConfig<'a> {\n    /// This is an internal function that should only be\n    /// called via the `filters` macro.\n    ///\n    /// This function calls Self::try_new(), but panics when an error is returned. This generates\n    /// a nice compile-time error, so long as `__filters()` is called from a `const` context. The purpose\n    /// of the `filters` macro is to ensure `__filters()` can only be called from a `const` context,\n    /// so we can do all the nice compile-time validation stuff without the possibility of a runtime panic.\n    #[doc(hidden)]\n    pub const fn __filters(filters: &'a [Filter]) -> Self {\n        match Self::try_new(filters) {\n            Ok(me) => me,\n            Err(FilterConfigError::TooManyFilters) => {\n                panic!(\n                    \"Invalid FilterConfig (TooManyFilters)! A FilterConfig must adhere to the constraint `2*(num_extended) + (num_standard) <= 32`.\"\n                );\n            }\n            Err(FilterConfigError::EmptyFilterConfig) => {\n                panic!(\"Invalid FilterConfig (EmptyFilterConfig)! A FilterConfig cannot be empty.\");\n            }\n        }\n    }\n\n    /// Creates a new `FilterConfig` from a declarative list of filters.\n    ///\n    /// The preferred way of constructing a `FilterConfig` is through the\n    /// `filters!()` macro (since it evaluates at compile-time), but this function\n    /// may be useful if you need to reconfigure filters based on runtime values.\n    pub const fn try_new(filters: &'a [Filter]) -> Result<Self, FilterConfigError> {\n        if filters.is_empty() {\n            return Err(FilterConfigError::EmptyFilterConfig);\n        }","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-mcxa/src/flexcan/filter.rs#L98-L134","documentation":"This panic occurs when a FlexCAN `FilterConfig` is built with too many filters. The hardware has 32 filter slots, and each extended (29-bit) filter consumes two slots while each standard (11-bit) filter consumes one, so `2*(num_extended) + (num_standard) <= 32` must hold. The const constructor `__filters` converts the `TooManyFilters` validation error from `try_new` into a compile-time-evaluable panic.","triggerScenarios":"Calling `FilterConfig::__filters(...)` (or the const constructor path) with a filter list where extended filters count double plus standard filters exceeds 32, e.g. 17 extended filters (34 slots) or 20 extended + 10 standard.","commonSituations":"Porting a CAN config from a driver with a larger filter bank; adding filters one at a time until the total silently crosses the hardware limit; forgetting extended filters cost two slots.","solutions":["Reduce the number of filters so `2*extended + standard <= 32`.","Prefer standard (11-bit) filters or merge overlapping ID ranges into fewer filters (hardware filter masks can cover ranges).","Switch to a single acceptance-mask filter covering a range instead of enumerating many exact IDs."],"exampleFix":"// before: 17 extended filters (17*2=34 > 32)\nlet cfg = FilterConfig::__filters(&[ext(0x18ff0100), /* ...16 more */]);\n// after: merge into range masks or drop to 16 extended\nlet cfg = FilterConfig::__filters(&[ext_range(0x18ff0100, 0x18ff01ff), /* 15 more */]);","handlingStrategy":"validation","validationCode":"// Count before constructing (non-const contexts):\nfn assert_fits(filters: &[Filter]) -> bool {\n    let cost: usize = filters.iter().map(|f| if f.is_extended() { 2 } else { 1 }).sum();\n    cost <= 32\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Track the 32-slot budget: extended filters cost 2, standard cost 1.","Use FilterConfig::try_new in runtime code and handle the error instead of the panicking const constructor.","Prefer masked range filters over enumerating many exact IDs."],"tags":["embedded","rust","can","filter","capacity-limit"],"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"}