embassy-rs/embassy · error

Invalid FilterConfig (EmptyFilterConfig)! A FilterConfig…

Error message

Invalid FilterConfig (EmptyFilterConfig)! A FilterConfig cannot be empty.

What it means

This panic fires when a FlexCAN `FilterConfig` is constructed from an empty filter list. The hardware message-buffer filter table must contain at least one filter; an empty table has no defined meaning, so `try_new` returns `EmptyFilterConfig` and the const constructor `__filters` turns that into a panic.

Solutions

  1. Pass at least one `Filter` to `__filters` (e.g. accept-all or the specific IDs you need).
  2. If 'receive everything' is intended, add a single catch-all filter rather than an empty list.
  3. Use `FilterConfig::try_new` first in non-const code to handle the error instead of panicking.

Example fix

// before
let cfg = FilterConfig::__filters(&[]);
// after
let cfg = FilterConfig::__filters(&[Filter::standard(0x123)]);
Defensive patterns

Strategy: validation

Validate before calling

if filters.is_empty() {
    // provide a default catch-all or bail before calling __filters
    panic!("at least one CAN filter required");
}

Prevention

When it happens

Trigger: Calling `FilterConfig::__filters(&[])` or passing a zero-length slice/array, often from a dynamically-built filter list that ended up empty.

Common situations: Building filters from a config file or user setting that specified none; a const-evaluated empty array after conditional filtering removed all entries; forgetting to add the first filter.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/d7b32445e06cdb80. Report an issue: GitHub.

Appendix: source

Thrown at embassy-mcxa/src/flexcan/filter.rs:121

impl<'a> FilterConfig<'a> {
    /// This is an internal function that should only be
    /// called via the `filters` macro.
    ///
    /// This function calls Self::try_new(), but panics when an error is returned. This generates
    /// a nice compile-time error, so long as `__filters()` is called from a `const` context. The purpose
    /// of the `filters` macro is to ensure `__filters()` can only be called from a `const` context,
    /// so we can do all the nice compile-time validation stuff without the possibility of a runtime panic.
    #[doc(hidden)]
    pub const fn __filters(filters: &'a [Filter]) -> Self {
        match Self::try_new(filters) {
            Ok(me) => me,
            Err(FilterConfigError::TooManyFilters) => {
                panic!(
                    "Invalid FilterConfig (TooManyFilters)! A FilterConfig must adhere to the constraint `2*(num_extended) + (num_standard) <= 32`."
                );
            }
            Err(FilterConfigError::EmptyFilterConfig) => {
                panic!("Invalid FilterConfig (EmptyFilterConfig)! A FilterConfig cannot be empty.");
            }
        }
    }

    /// Creates a new `FilterConfig` from a declarative list of filters.
    ///
    /// The preferred way of constructing a `FilterConfig` is through the
    /// `filters!()` macro (since it evaluates at compile-time), but this function
    /// may be useful if you need to reconfigure filters based on runtime values.
    pub const fn try_new(filters: &'a [Filter]) -> Result<Self, FilterConfigError> {
        if filters.is_empty() {
            return Err(FilterConfigError::EmptyFilterConfig);
        }

        // Calculate how many of each type of filter there is
        let mut num_standard = 0;
        let mut num_extended = 0;
        let mut i = 0;

View on GitHub (pinned to 463a07b963)