{"record":{"id":"861519be0a23d0e0","repo":"aaif-goose/goose","slug":"cannot-parse-shard-total-from","errorCode":null,"errorMessage":"Cannot parse shard total from '{}'","messagePattern":"Cannot parse shard total from '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-local-inference/src/hf_models.rs","lineNumber":838,"sourceCode":"        };\n        let total_size = file.size_bytes;\n        return Ok((\n            repo_id,\n            ResolvedModel {\n                files: vec![file],\n                total_size,\n                mmproj,\n            },\n        ));\n    }\n\n    // Use shards, sorted by filename so shard 1 is first\n    shard_files.sort_by(|a, b| a.rfilename.cmp(&b.rfilename));\n\n    // Validate shard set completeness: every file must parse to the same\n    // -of-N total, and indices must be contiguous 1..=N.\n    let expected_total = parse_shard_total(&shard_files[0].rfilename).ok_or_else(|| {\n        anyhow::anyhow!(\n            \"Cannot parse shard total from '{}'\",\n            shard_files[0].rfilename\n        )\n    })?;\n    if shard_files.len() != expected_total as usize {\n        bail!(\n            \"Incomplete shard set for '{}' in {}: found {} of {} shards\",\n            quant,\n            repo_id,\n            shard_files.len(),\n            expected_total\n        );\n    }\n    for (i, shard) in shard_files.iter().enumerate() {\n        let shard_total = parse_shard_total(&shard.rfilename);\n        if shard_total != Some(expected_total) {\n            bail!(\n                \"Inconsistent shard totals for '{}' in {}: shard '{}' has total {:?}, expected {}\",","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-local-inference/src/hf_models.rs#L820-L856","documentation":"In resolve_model_spec_full's shard validation: a GGUF sibling was classified as a shard because parse_shard_index found all-digit text before '-of-' (is_shard_file), but parse_shard_total could not parse the text after the last '-of-' as a u32. That happens when the suffix after '-of-' is not a plain number (e.g. 'model-00001-of-latest.gguf') or carries extra trailing segments. Validation aborts before the file list is built.","triggerScenarios":"Resolving a quantization whose repo contains GGUF files matching the shard-index heuristic ('-digits-of-') but with a non-numeric or mangled total, e.g. 'model-BF16-00001-of-00002-v2.gguf' or 'model-00001-of-latest.gguf'.","commonSituations":"Upstream repos with unconventional shard naming; renames or re-uploads that break the 'model-XXXXX-of-XXXXX.gguf' convention; single-file repos accidentally matching the index heuristic.","solutions":["Pick a quantization or repo that ships standard 'model-00001-of-00003.gguf' naming, or a single-file (non-sharded) GGUF","Check the repo's file list on huggingface.co to see which filename breaks the pattern named in the error","If the repo should work, report the exact filename as a parser edge case"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// mirror the library's shard-total parser to preflight a repo's filenames\nfn shard_total_parses(filename: &str) -> bool {\n    let stem = filename.rsplit('/').next().unwrap_or(filename).trim_end_matches(\".gguf\");\n    stem.rfind(\"-of-\").and_then(|p| stem.get(p + 4..)).and_then(|t| t.parse::<u32>().ok()).is_some()\n}","typeGuard":"fn has_standard_shard_naming(filenames: &[String]) -> bool {\n    filenames.iter().all(|f| !f.contains(\"-of-\") || shard_total_parses(f))\n}","tryCatchPattern":"if err.to_string().starts_with(\"Cannot parse shard total\") {\n    // repo naming is nonstandard: switch to a repo with model-XXXXX-of-XXXXX.gguf files\n    // or a single-file quantization; retrying the same spec cannot succeed\n}","preventionTips":["Curate recommended repos and verify their shard naming once, not per-download","Check the repo file list on huggingface.co before offering a quantization","Report filenames that match the index heuristic but break the total parser as bugs"],"tags":["rust","huggingface","gguf","sharding","parsing"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}