astral-sh/ruff · info

module to include at least one segment

Error message

module to include at least one segment

What it means

isort's `module_base` returns the first dot-separated segment of a module name (e.g. `foo` from `foo.bar.baz`). The `.expect("module to include at least one segment")` encodes the invariant that `str::split` always yields at least one item — which is true for any &str, since splitting never produces an empty iterator. The panic is therefore unreachable for borrowed module names.

Source

Thrown at crates/ruff_linter/src/rules/isort/types.rs:51

}

#[derive(Debug, Default, Clone)]
pub(crate) struct ImportFromCommentSet<'a> {
    pub(crate) atop: Vec<Cow<'a, str>>,
    pub(crate) inline: Vec<Cow<'a, str>>,
    pub(crate) trailing: Vec<Cow<'a, str>>,
}

pub(crate) trait Importable<'a> {
    fn module_name(&self) -> Cow<'a, str>;

    fn module_base(&self) -> Cow<'a, str> {
        match self.module_name() {
            Cow::Borrowed(module_name) => Cow::Borrowed(
                module_name
                    .split('.')
                    .next()
                    .expect("module to include at least one segment"),
            ),
            Cow::Owned(module_name) => Cow::Owned(
                module_name
                    .split('.')
                    .next()
                    .expect("module to include at least one segment")
                    .to_owned(),
            ),
        }
    }
}

impl<'a> Importable<'a> for AliasData<'a> {
    fn module_name(&self) -> Cow<'a, str> {
        Cow::Borrowed(self.name)
    }
}

View on GitHub (pinned to 26f38c119c)

Solutions

  1. Leave as-is: split().next() on a &str is infallible; consider documenting the invariant in the comment
  2. If desired, use `match module_name.split('.').next() { Some(base) => ..., None => unreachable via types }` or model the module name as a non-empty type
  3. Avoid switching to a filtering split that could legitimately return empty

Example fix

// before
module_name.split('.').next().expect("module to include at least one segment")
// after
// split always yields at least one item; keep expect or switch to a non-empty type
module_name.split('.').next().unwrap_or(module_name)
Defensive patterns

Strategy: fallback

Type guard

fn module_base_safe(name: &str) -> &str { name.split('.').next().unwrap_or(name) }

Prevention

When it happens

Trigger: Not triggerable by user input: `"".split('.')` still yields one empty string. It could only fire if the code were changed to a different splitting method (e.g. a filter that drops empty segments) or if module_name could be a non-str type.

Common situations: Contributors hit this only as a false-positive code smell (clippy/analysis tools flagging the expect) or when refactoring module_name to an Option<Vec<Segment>> representation.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/973fbc4e664594b5. Report an issue: GitHub.