astral-sh/ruff · error
Expected at least one import
Error message
Expected at least one import
What it means
Same pattern as the TC004 fix: `fix_imports` (for typing-only runtime imports, TC002) anchors its edits at the earliest reference start of the collected bindings and panics if `imports` is empty. The invariant is that the function only runs when at least one import binding needs moving into a type-checking block.
Source
Thrown at crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs:531
/// Generate a [`Fix`] to remove typing-only imports from a runtime context.
fn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {
let statement = checker.semantic().statement(node_id);
let parent = checker.semantic().parent_statement(node_id);
let member_names: Vec<Cow<'_, str>> = imports
.iter()
.map(|ImportBinding { import, .. }| import)
.map(Imported::member_name)
.collect();
// Find the first reference across all imports.
let at = imports
.iter()
.map(|ImportBinding { reference_id, .. }| {
checker.semantic().reference(*reference_id).start()
})
.min()
.expect("Expected at least one import");
let add_future_import = imports.iter().any(|binding| binding.needs_future_import);
// Step 1) Remove the import.
let remove_import_edit = fix::edits::remove_unused_imports(
member_names.iter().map(AsRef::as_ref),
statement,
parent,
checker.locator(),
checker.stylist(),
checker.indexer(),
)?;
// Step 2) Add the import to a `TYPE_CHECKING` block.
let (type_checking_edit, add_import_edit) = checker
.importer()
.typing_import_edit(
&ImportedMembers {View on GitHub (pinned to 26f38c119c)
Solutions
- Guard with an early return producing Fix::empty() when imports is empty
- Keep the presence check and the fix builder reading the same (unchanged) bindings vector
- Handle the Option from min() explicitly instead of expecting
Example fix
// before
let at = imports.iter().map(...).min().expect("Expected at least one import");
// after
let Some(at) = imports.iter().map(...).min() else { return Fix::empty(); }; Defensive patterns
Strategy: validation
Validate before calling
if imports.is_empty() { return Fix::empty(); } Type guard
if let [first, ..] = imports { /* anchor from first */ } Prevention
- Anchor edits only from a verified non-empty binding list
- Keep presence checks and fix construction reading the same vector
- Prefer Option-returning min over expect
When it happens
Trigger: fix_imports is reached with an empty bindings list — the diagnostic decided a fix exists, but binding collection produced nothing (e.g. every binding lacked a resolvable reference id or was deduplicated away).
Common situations: Contributors encounter this after changing reference resolution or the ImportBinding filter so the presence-check upstream no longer matches the actual list contents.
Related errors
- Expected at least one import
- Expected at least one reference
- extra use-def data should have been retained
- should be set because `extract_if` only yields elements with
- Should only ever pass a positive integer to `from_nonnegativ
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/1bcb619cb47cf6cc.
Report an issue: GitHub.