{"record":{"id":"9bd618a121787798","repo":"AlexsJones/llmfit","slug":"files-list-is-not-empty","errorCode":null,"errorMessage":"files list is not empty","messagePattern":"files list is not empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"llmfit-tui/src/main.rs","lineNumber":1668,"sourceCode":"            let specs = detect_specs(overrides);\n            specs\n                .total_gpu_vram_gb\n                .or(Some(specs.available_ram_gb))\n                .unwrap_or(16.0)\n        };\n        if let Some(result) = LlamaCppProvider::select_best_gguf(&files, mem_budget) {\n            println!(\n                \"Selected {} ({:.1} GB) for {:.0} GB memory budget\",\n                result.0,\n                result.1 as f64 / 1_073_741_824.0,\n                mem_budget\n            );\n            result\n        } else {\n            // Nothing fits — pick smallest\n            let mut sorted = files.clone();\n            sorted.sort_by_key(|(_, s)| *s);\n            let (f, s) = sorted.first().expect(\"files list is not empty\");\n            println!(\n                \"Warning: No quantization fits within {:.0} GB. Downloading smallest: {} ({:.1} GB)\",\n                mem_budget,\n                f,\n                *s as f64 / 1_073_741_824.0\n            );\n            (f.clone(), *s)\n        }\n    };\n\n    // If the selected file is one shard of a multi-part model, expand it\n    // here so we can show the user the full size and part count up front.\n    // The actual download is still driven by `download_gguf`, which performs\n    // the same expansion internally.\n    let shard_set = llmfit_core::providers::collect_shard_set(&files, &filename);\n    let (display_name, display_size) = if let Some(ref shards) = shard_set {\n        let total: u64 = shards.iter().map(|(_, s)| *s).sum();\n        let first = shards[0].0.clone();","sourceCodeStart":1650,"sourceCodeEnd":1686,"githubUrl":"https://github.com/AlexsJones/llmfit/blob/acc7e40c3a0afbd36510a92f2f8f3d5177cfc0fe/llmfit-tui/src/main.rs#L1650-L1686","documentation":"Panic from sorted.first().expect(\"files list is not empty\") in the GGUF auto-select fallback (main.rs:1664-1676). The flow earlier fetches repo files via LlamaCppProvider::list_repo_gguf_files and exits with a friendly error at main.rs:1603-1607 when files.is_empty(), so by the time this branch runs (no quantization fits the memory budget, pick the smallest) the Vec is provably non-empty. The expect documents that established invariant; in the current code it is unreachable, and firing it means the upstream guard was removed, reordered, or the selection started operating on a different collection.","triggerScenarios":"Only reachable in `llmfit download <repo>` (auto-select path, no --quant) if the empty-check at main.rs:1603 is deleted or moved after selection, or if a refactor passes a different/filtered files Vec into the fallback. A repo whose file list changes between the check and use cannot cause it — the same Vec is cloned and sorted.","commonSituations":"Contributor refactors of the download command that extract the auto-select logic into a helper without carrying the emptiness guard; code paths where list_repo_gguf_files' error handling changes to return an empty Vec silently on network failure instead of the caller exiting.","solutions":["If you hit this panic in a dev build, check git diff for changes to the files.is_empty() guard at llmfit-tui/src/main.rs:1603 — restoring it (exit with the 'No GGUF files found' message) is the fix.","Keep the guard in the same function as the selection so extraction into a helper cannot drop it, or convert the expect into an explicit empty-handling branch.","Verify list_repo_gguf_files still fails loud (not silently-empty) on network/API errors.","For end users seeing this in a released binary: report it as a bug — the invariant held at release time."],"exampleFix":"// before\nlet mut sorted = files.clone();\nsorted.sort_by_key(|(_, s)| *s);\nlet (f, s) = sorted.first().expect(\"files list is not empty\");\n\n// after — make the guard local instead of relying on a distant check\nlet mut sorted = files.clone();\nsorted.sort_by_key(|(_, s)| *s);\nlet Some((f, s)) = sorted.first() else {\n    eprintln!(\"No GGUF files found in repository '{repo_id}'.\");\n    std::process::exit(1);\n};","handlingStrategy":"validation","validationCode":"// Guard the collection before entering any auto-select/first() logic.\nif files.is_empty() {\n    eprintln!(\"No GGUF files found in repository '{repo_id}'.\");\n    eprintln!(\"Make sure this is a valid GGUF repository on HuggingFace.\");\n    std::process::exit(1);\n}\nlet (filename, file_size) = select_or_smallest(&files, mem_budget);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the is_empty() check in the same function as the smallest-file fallback so refactors cannot separate them.","Prefer let-else over expect when unwrapping collection heads in CLI paths: `let Some((f, s)) = sorted.first() else { exit(1) };`.","When extracting download helpers, make them return Result and let the caller decide the exit path.","Ensure list_repo_gguf_files surfaces network/API failures as errors, not as an empty Vec."],"tags":["rust","panic","internal-invariant","huggingface","gguf-download"],"backgroundTag":"empty-collection-unwrap","analyzedSha":"acc7e40c3a0afbd36510a92f2f8f3d5177cfc0fe","analyzedAt":"2026-08-17T10:35:29.658Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}