{"record":{"id":"5c0536176d532882","repo":"aaif-goose/goose","slug":"model-not-found-5c0536","errorCode":null,"errorMessage":"Model not found","messagePattern":"Model not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-local-inference/src/management.rs","lineNumber":206,"sourceCode":"pub fn download_progress(model_id: &str) -> Result<Option<LocalInferenceDownloadProgressDto>> {\n    Ok(get_download_manager()\n        .get_progress(&format!(\"{}-model\", model_id))\n        .map(download_progress_to_dto))\n}\n\npub fn cancel_download(model_id: &str) -> Result<()> {\n    let manager = get_download_manager();\n    manager.cancel_download(&format!(\"{}-model\", model_id))?;\n    let _ = manager.cancel_download(&format!(\"{}-mmproj\", model_id));\n    Ok(())\n}\n\npub fn delete_model(model_id: &str) -> Result<()> {\n    let mut registry = get_registry()\n        .lock()\n        .map_err(|_| anyhow!(\"Failed to acquire registry lock\"))?;\n    if registry.get_model(model_id).is_none() {\n        anyhow::bail!(\"Model not found\");\n    }\n    registry.delete_model(model_id)\n}\n\npub fn model_exists(model_id: &str) -> Result<bool> {\n    let registry = get_registry()\n        .lock()\n        .map_err(|_| anyhow!(\"Failed to acquire registry lock\"))?;\n    Ok(registry.get_model(model_id).is_some())\n}\n\npub async fn evict_model(model_id: &str) -> Result<()> {\n    crate::evict_model(model_id)\n        .await\n        .map(|_| ())\n        .map_err(|error| anyhow!(error.to_string()))\n}\n","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-local-inference/src/management.rs#L188-L224","documentation":"delete_model() looks up model_id in the registry and bails with 'Model not found' when registry.get_model(model_id) is None. The registry only contains models previously registered by the download flow (llamacpp ids look like 'owner/repo:QUANT', mlx ids like 'owner/repo'). This is a plain not-found condition, not corruption. The lookup happens under the lock, so the model must match exactly, byte for byte.","triggerScenarios":"Deleting with a malformed or non-registered id: passing 'Qwen/Qwen2.5-7B' (no :Q4_K_M quant suffix) for a llamacpp model; deleting a model that was already deleted (double-delete); passing an id from a different data dir / GOOSE_HOME than the one the registry persists in; case or whitespace mismatch.","commonSituations":"UI holds a stale list after the model was removed elsewhere; user hand-copies an id and drops the quantization suffix; registry.json was recreated after a data-dir wipe or migration; scripted cleanup re-running after partial success.","solutions":["Call list_models() and use the exact id it returns (note the 'owner/repo:QUANT' shape for llama.cpp models).","Confirm the process uses the same data directory / GOOSE_HOME as the one where the model was downloaded.","Make deletion idempotent in the caller: treat 'Model not found' as success when reconciling state.","If the model directory exists on disk but is not listed, re-download or manually remove the files — the registry is the source of truth for delete_model."],"exampleFix":"// before\nmanagement::delete_model(&model_id)?; // errors 'Model not found' on stale id\n\n// after: reconcile against the registry first\nlet models = management::list_models().await?;\nlet exact = models.models.iter().find(|m| m.id == model_id)\n    .map(|m| m.id.clone());\nif let Some(id) = exact {\n    management::delete_model(&id)?;\n}","handlingStrategy":"validation","validationCode":"let models = management::list_models().await?;\nlet exists = models.models.iter().any(|m| m.id == model_id);\nif !exists {\n    return Ok(()); // already gone — treat delete as idempotent\n}\nmanagement::delete_model(model_id)?;","typeGuard":"fn is_registered_model_id(models: &LocalInferenceModelsListResponse, id: &str) -> bool {\n    models.models.iter().any(|m| m.id == id)\n}","tryCatchPattern":"match management::delete_model(model_id) {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string().contains(\"Model not found\") => Ok(()), // idempotent delete\n    Err(e) => Err(e),\n}","preventionTips":["Always source model ids from list_models(), never construct them by hand.","Remember llama.cpp ids embed the quantization: 'owner/repo:Q4_K_M'.","Verify both processes use the same GOOSE_HOME/data dir before cross-checking ids.","Make scripted deletes idempotent by swallowing 'Model not found'."],"tags":["rust","validation","model-not-found","delete-model","local-inference","registry"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}