aaif-goose/goose · error

Unknown model: {}

Error message

Unknown model: {}

What it means

transcribe_local resolves LOCAL_WHISPER_MODEL through whisper::get_model, which is an exact-match lookup over the static MODELS catalog containing only the ids "tiny", "base", "small", and "medium" (whisper.rs:61-79). Any other string returns None and becomes this error. Note the catalog is stricter than whisper's internal Config fallback, which would silently fall back to tiny for unknown ids.

Source

Thrown at crates/goose/src/dictation/providers.rs:145

        _ => {
            let def = get_provider_def(provider);
            config.get_secret::<String>(def.config_key).is_ok()
        }
    }
}

#[cfg(feature = "local-inference")]
pub async fn transcribe_local(audio_bytes: Vec<u8>) -> Result<String> {
    tokio::task::spawn_blocking(move || {
        let config = Config::global();
        let model_id = config
            .get(LOCAL_WHISPER_MODEL_CONFIG_KEY, false)
            .ok()
            .and_then(|v| v.as_str().map(|s| s.to_string()))
            .ok_or_else(|| anyhow::anyhow!("Local Whisper model not configured"))?;

        let model = super::whisper::get_model(&model_id)
            .ok_or_else(|| anyhow::anyhow!("Unknown model: {}", model_id))?;
        let model_path = model.local_path();

        let mut transcriber_lock = LOCAL_TRANSCRIBER
            .lock()
            .map_err(|e| anyhow::anyhow!("Failed to lock transcriber: {}", e))?;

        let model_path_str = model_path.to_string_lossy().to_string();
        let needs_reload = match transcriber_lock.as_ref() {
            None => true,
            Some((cached_path, _)) => cached_path != &model_path_str,
        };

        if needs_reload {
            tracing::info!("Loading Whisper model from: {}", model_path.display());

            let transcriber = super::whisper::WhisperTranscriber::new_with_tokenizer(
                &model_id,
                &model_path,

View on GitHub (pinned to 3810898a74)

Solutions

  1. Set LOCAL_WHISPER_MODEL to exactly one of: tiny, base, small, medium
  2. Pick programmatically with recommend_model() or list valid ids via available_models()

Example fix

# before
goose config set --params LOCAL_WHISPER_MODEL large-v3

# after
goose config set --params LOCAL_WHISPER_MODEL small
Defensive patterns

Strategy: validation

Validate before calling

use goose::dictation::whisper::{available_models, get_model};

fn model_id_supported(id: &str) -> bool {
    get_model(id).is_some()
}

// validate before transcribing, or offer the valid set:
let ids: Vec<&str> = available_models().iter().map(|m| m.id).collect();

Type guard

fn model_id_supported(id: &str) -> bool {
    goose::dictation::whisper::get_model(id).is_some() // ids: tiny | base | small | medium
}

Prevention

When it happens

Trigger: LOCAL_WHISPER_MODEL set to an unsupported value: "large", "whisper-small", "small.en", "Small" (case-sensitive), or a value with trailing whitespace.

Common situations: Copying a model name from OpenAI's API docs (large-v3, whisper-1) instead of goose's local ids; hand-editing the config file; case or whitespace mistakes.

Related errors


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