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.
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
- -32603
- accumulator should not be empty
- anchor should not be NodeIndex::NONE
AI-assisted analysis of astral-sh/ruff@5bb508f594 (2026-09-05).
Data as JSON: /api/errors/1bcb619cb47cf6cc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs:643
statement.start(),
)));
}
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 5bb508f594)