{"record":{"id":"1bcb619cb47cf6cc","repo":"astral-sh/ruff","slug":"expected-at-least-one-import-1bcb61","errorCode":null,"errorMessage":"Expected at least one import","messagePattern":"Expected at least one import","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs","lineNumber":531,"sourceCode":"/// Generate a [`Fix`] to remove typing-only imports from a runtime context.\nfn fix_imports(checker: &Checker, node_id: NodeId, imports: &[ImportBinding]) -> Result<Fix> {\n    let statement = checker.semantic().statement(node_id);\n    let parent = checker.semantic().parent_statement(node_id);\n\n    let member_names: Vec<Cow<'_, str>> = imports\n        .iter()\n        .map(|ImportBinding { import, .. }| import)\n        .map(Imported::member_name)\n        .collect();\n\n    // Find the first reference across all imports.\n    let at = imports\n        .iter()\n        .map(|ImportBinding { reference_id, .. }| {\n            checker.semantic().reference(*reference_id).start()\n        })\n        .min()\n        .expect(\"Expected at least one import\");\n\n    let add_future_import = imports.iter().any(|binding| binding.needs_future_import);\n\n    // Step 1) Remove the import.\n    let remove_import_edit = fix::edits::remove_unused_imports(\n        member_names.iter().map(AsRef::as_ref),\n        statement,\n        parent,\n        checker.locator(),\n        checker.stylist(),\n        checker.indexer(),\n    )?;\n\n    // Step 2) Add the import to a `TYPE_CHECKING` block.\n    let (type_checking_edit, add_import_edit) = checker\n        .importer()\n        .typing_import_edit(\n            &ImportedMembers {","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs#L513-L549","documentation":"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.","triggerScenarios":"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).","commonSituations":"Contributors encounter this after changing reference resolution or the ImportBinding filter so the presence-check upstream no longer matches the actual list contents.","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"],"exampleFix":"// before\nlet at = imports.iter().map(...).min().expect(\"Expected at least one import\");\n// after\nlet Some(at) = imports.iter().map(...).min() else { return Fix::empty(); };","handlingStrategy":"validation","validationCode":"if imports.is_empty() { return Fix::empty(); }","typeGuard":"if let [first, ..] = imports { /* anchor from first */ }","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","panic","empty-collection","imports"],"backgroundTag":"empty-collection-panic","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}