aaif-goose/goose · error

Model not found

Error message

Model not found

What it means

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.

Source

Thrown at crates/goose-local-inference/src/management.rs:206

pub fn download_progress(model_id: &str) -> Result<Option<LocalInferenceDownloadProgressDto>> {
    Ok(get_download_manager()
        .get_progress(&format!("{}-model", model_id))
        .map(download_progress_to_dto))
}

pub fn cancel_download(model_id: &str) -> Result<()> {
    let manager = get_download_manager();
    manager.cancel_download(&format!("{}-model", model_id))?;
    let _ = manager.cancel_download(&format!("{}-mmproj", model_id));
    Ok(())
}

pub fn delete_model(model_id: &str) -> Result<()> {
    let mut registry = get_registry()
        .lock()
        .map_err(|_| anyhow!("Failed to acquire registry lock"))?;
    if registry.get_model(model_id).is_none() {
        anyhow::bail!("Model not found");
    }
    registry.delete_model(model_id)
}

pub fn model_exists(model_id: &str) -> Result<bool> {
    let registry = get_registry()
        .lock()
        .map_err(|_| anyhow!("Failed to acquire registry lock"))?;
    Ok(registry.get_model(model_id).is_some())
}

pub async fn evict_model(model_id: &str) -> Result<()> {
    crate::evict_model(model_id)
        .await
        .map(|_| ())
        .map_err(|error| anyhow!(error.to_string()))
}

View on GitHub (pinned to 3810898a74)

Solutions

  1. Call list_models() and use the exact id it returns (note the 'owner/repo:QUANT' shape for llama.cpp models).
  2. Confirm the process uses the same data directory / GOOSE_HOME as the one where the model was downloaded.
  3. Make deletion idempotent in the caller: treat 'Model not found' as success when reconciling state.
  4. 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.

Example fix

// before
management::delete_model(&model_id)?; // errors 'Model not found' on stale id

// after: reconcile against the registry first
let models = management::list_models().await?;
let exact = models.models.iter().find(|m| m.id == model_id)
    .map(|m| m.id.clone());
if let Some(id) = exact {
    management::delete_model(&id)?;
}
Defensive patterns

Strategy: validation

Validate before calling

let models = management::list_models().await?;
let exists = models.models.iter().any(|m| m.id == model_id);
if !exists {
    return Ok(()); // already gone — treat delete as idempotent
}
management::delete_model(model_id)?;

Type guard

fn is_registered_model_id(models: &LocalInferenceModelsListResponse, id: &str) -> bool {
    models.models.iter().any(|m| m.id == id)
}

Try / catch

match management::delete_model(model_id) {
    Ok(()) => Ok(()),
    Err(e) if e.to_string().contains("Model not found") => Ok(()), // idempotent delete
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/5c0536176d532882. Report an issue: GitHub.