{"record":{"id":"c3dd82beb7547d35","repo":"aaif-goose/goose","slug":"invalid-repo-id-expected-owner-name","errorCode":null,"errorMessage":"Invalid repo id '{}': expected owner/name","messagePattern":"Invalid repo id '(.+?)': expected owner/name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-local-inference/src/hf_models.rs","lineNumber":1510,"sourceCode":"}\n\nasync fn hf_client() -> Result<HFClient> {\n    let mut builder = HFClient::builder().user_agent(\"goose-ai-agent\");\n    if let Some(token) = optional_hf_token(huggingface_auth::resolve_token_async()).await {\n        builder = builder.token(token);\n    }\n    builder.build().map_err(Into::into)\n}\n\nfn model_repo(client: &HFClient, repo_id: &str) -> Result<HFRepository<RepoTypeModel>> {\n    let (owner, name) = split_repo_id(repo_id)?;\n    Ok(client.model(owner, name))\n}\n\nfn split_repo_id(repo_id: &str) -> Result<(&str, &str)> {\n    repo_id\n        .split_once('/')\n        .ok_or_else(|| anyhow::anyhow!(\"Invalid repo id '{}': expected owner/name\", repo_id))\n}\n\nasync fn search_mlx_models(query: &str, limit: usize) -> Result<Vec<HfModelInfo>> {\n    let mut results = search_mlx_models_with_query(query, limit).await?;\n    if !query.contains('/') {\n        results\n            .extend(search_mlx_models_with_query(&format!(\"mlx-community/{query}\"), limit).await?);\n        results.extend(search_mlx_models_with_query(&format!(\"google/{query}\"), limit).await?);\n    }\n    dedupe_models(&mut results);\n    results.truncate(limit);\n    Ok(results)\n}\n\nasync fn search_mlx_models_with_query(query: &str, limit: usize) -> Result<Vec<HfModelInfo>> {\n    let client = hf_client().await?;\n    let stream = client\n        .list_models()","sourceCodeStart":1492,"sourceCodeEnd":1528,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-local-inference/src/hf_models.rs#L1492-L1528","documentation":"split_repo_id requires a '/' in the repo id (split_once('/')) and is used by model_repo and download_gguf_to_hf_cache to build HF API/download requests. Bare names or empty strings fail here. Note only the presence of a slash is checked: '/name' or 'a/b/c' pass this check with empty or compound parts and fail later at the HF API with a 404-style error instead.","triggerScenarios":"Calling the GGUF download/resolve path with a bare model name like 'Llama-3.2-1B-Instruct-GGUF', an empty string, or a value trimmed of its owner prefix by UI code.","commonSituations":"Search-driven flows returning bare names; configs storing only the short title; copy-paste from HF URLs that drops the owner segment.","solutions":["Use the full 'owner/name' id exactly as it appears in the huggingface.co URL, e.g. 'bartowski/Llama-3.2-1B-Instruct-GGUF'","If you only have a bare name, resolve it through model search first to obtain the full id","Normalize/validate ids at your config boundary so partial ids never reach the resolver"],"exampleFix":"// before\nlet repo = client.model(repo_id, String::new()); // or passing a bare name downstream\n\n// after: validate shape once at the edge\nlet (owner, name) = repo_id\n    .split_once('/')\n    .filter(|(o, n)| !o.is_empty() && !n.is_empty() && !n.contains('/'))\n    .with_context(|| format!(\"expected 'owner/name', got '{repo_id}'\"))?;","handlingStrategy":"validation","validationCode":"anyhow::ensure!(\n    matches!(repo_id.split_once('/'), Some((o, n)) if !o.is_empty() && !n.is_empty() && !n.contains('/')),\n    \"repo id must be 'owner/name', got '{repo_id}'\"\n);","typeGuard":"fn is_valid_repo_id(repo_id: &str) -> bool {\n    matches!(repo_id.split_once('/'), Some((owner, name)) if !owner.is_empty() && !name.is_empty() && !name.contains('/'))\n}","tryCatchPattern":"match split_repo_id_result {\n    Err(e) if e.to_string().contains(\"expected owner/name\") => {\n        // resolve the bare name through model search to get the full id\n    }\n    other => other,\n}","preventionTips":["Store and pass full 'owner/name' ids end to end; never strip the owner segment","Validate the id shape where it enters your system (config load, CLI args)","Copy ids from the huggingface.co URL to avoid transcription drift"],"tags":["rust","validation","huggingface","parsing"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}