Hmbown/CodeWhale · error

Failed to parse Ollama /api/tags JSON

Error message

Failed to parse Ollama /api/tags JSON: {err}

What it means

Raised when the native Ollama `GET /api/tags` response body fails `serde_json` deserialization into the OllamaTagsResponse struct. The payload is either not JSON at all (HTML error page, proxy response) or does not match the expected shape (missing `models` array, wrong field types).

Solutions

  1. Verify the Ollama server is reachable at the expected host/port (`curl http://localhost:11434/api/tags`)
  2. Log or print the raw payload to see what was actually returned
  3. Update the OllamaTagsResponse struct / check the Ollama version's schema
  4. Skip or downgrade the local catalog probe on parse failure instead of failing the listing

Example fix

// before
let parsed: OllamaTagsResponse = serde_json::from_str(payload)
    .map_err(|err| anyhow::anyhow!("Failed to parse Ollama /api/tags JSON: {err}"))?;
// after (tolerate non-JSON bodies)
match serde_json::from_str::<OllamaTagsResponse>(payload) {
    Ok(parsed) => { /* ... */ }
    Err(err) => tracing::warn!("ollama /api/tags not JSON: {err}; body starts: {}", &payload[..payload.len().min(120)]),
}
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeOllamaTags(body) {
  const j = safeJsonParse(body);
  return j && Array.isArray(j.models) && j.models.every(m => typeof m.name === 'string');
}

Type guard

fn is_tags_payload(v: &serde_json::Value) -> bool {
    v.get("models").map(|m| m.is_array()).unwrap_or(false)
}

Try / catch

match parse_ollama_tags_response(&body) {
    Ok(tags) => tags,
    Err(e) => { log::warn!("ollama catalog unavailable: {e}"); Vec::new() }
}

Prevention

When it happens

Trigger: `parse_ollama_tags_response` receiving a body that is empty, truncated, HTML/plain text, or whose `models` entries lack required fields with the expected types.

Common situations: Ollama not running so a proxy/portal answers with HTML; Ollama version with a changed /api/tags schema; a reverse proxy returning an error page; hitting a non-Ollama port.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/3067e88bcf002af4. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/local_ollama.rs:84

#[derive(Debug, Deserialize)]
struct OllamaTagsResponse {
    #[serde(default)]
    models: Vec<OllamaTagModel>,
}

#[derive(Debug, Deserialize)]
struct OllamaTagModel {
    #[serde(default)]
    name: String,
    #[serde(default)]
    model: String,
}

/// Parse native Ollama `GET /api/tags` JSON into sorted unique tag ids.
pub(crate) fn parse_ollama_tags_response(payload: &str) -> anyhow::Result<Vec<String>> {
    let parsed: OllamaTagsResponse = serde_json::from_str(payload)
        .map_err(|err| anyhow::anyhow!("Failed to parse Ollama /api/tags JSON: {err}"))?;
    let mut tags: Vec<String> = parsed
        .models
        .into_iter()
        .filter_map(|row| {
            let name = row.name.trim();
            if !name.is_empty() {
                return Some(name.to_string());
            }
            let model = row.model.trim();
            if !model.is_empty() {
                Some(model.to_string())
            } else {
                None
            }
        })
        .collect();
    tags.sort();
    tags.dedup();

View on GitHub (pinned to 73e0f67d83)