Ollama: only treat a 404 as model-not-found when the body says so
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m31s
CI / ci (pull_request) Successful in 1m29s

A 404 from a proxy without /api/chat, or any other 404 error, was
reported as the configured model being missing. Generate now checks the
{"error": ...} payload for Ollama's model-not-found message naming the
configured model (double- or single-quoted); any other 404 stays a
ProviderError with its redacted body excerpt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 08:37:22 -04:00
co-authored by Claude Opus 5.5
parent d5fe7548c5
commit 1d4c0bd0e1
2 changed files with 61 additions and 3 deletions
+18 -3
View File
@@ -138,9 +138,9 @@ func (p *Provider) Generate(ctx context.Context, req llm.Request) (llm.Response,
raw, err := p.do(ctx, http.MethodPost, "/api/chat", payload)
if err != nil {
var pe *llm.ProviderError
if errors.As(err, &pe) && pe.Status() == http.StatusNotFound {
// Ollama answers 404 when the model is not pulled. The body is
// not quoted: the model name is all the caller needs.
if errors.As(err, &pe) && pe.Status() == http.StatusNotFound && p.modelNotFound(pe.Body()) {
// The body is not quoted: the model name is all the caller
// needs. Any other 404 keeps its body excerpt below.
return llm.Response{}, fmt.Errorf("ollama: generate: model %q not found: %w", p.model, llm.NewProviderError(pe.Status(), nil, ""))
}
return llm.Response{}, fmt.Errorf("ollama: generate: %w", err)
@@ -169,6 +169,21 @@ func (p *Provider) Generate(ctx context.Context, req llm.Request) (llm.Response,
return resp, fmt.Errorf("ollama: generate: reply is not a JSON object: %w", llm.ErrBadOutput)
}
// modelNotFound reports whether body is Ollama's error for the configured
// model not being pulled: {"error": "model \"name\" not found, ..."}, or
// with the name in single quotes as newer servers send it. A 404 from
// anything else, such as a proxy without /api/chat, is not.
func (p *Provider) modelNotFound(body string) bool {
var e struct {
Error string `json:"error"`
}
if err := json.Unmarshal([]byte(body), &e); err != nil {
return false
}
return strings.HasPrefix(e.Error, fmt.Sprintf("model %q not found", p.model)) ||
strings.HasPrefix(e.Error, fmt.Sprintf("model '%s' not found", p.model))
}
// isJSONObject reports whether s is exactly one JSON object.
func isJSONObject(s string) bool {
return strings.HasPrefix(s, "{") && json.Valid([]byte(s))