micro/go-micro · error

failed to parse response: %w

Error message

failed to parse response: %w

What it means

This error wraps a json.Unmarshal failure when decoding the Ollama OpenAI-compatible chat response in callOpenAI. It means the response body could not be parsed into the expected choices struct — commonly because the server returned an error page, plain-text error, or a schema the struct does not match.

Source

Thrown at ai/ollama/ollama.go:275

			TotalTokens      int `json:"total_tokens"`
		} `json:"usage"`
		Choices []struct {
			Message struct {
				Role      string `json:"role"`
				Content   string `json:"content"`
				ToolCalls []struct {
					ID       string `json:"id"`
					Function struct {
						Name      string `json:"name"`
						Arguments string `json:"arguments"`
					} `json:"function"`
				} `json:"tool_calls"`
			} `json:"message"`
		} `json:"choices"`
	}

	if err := json.Unmarshal(respBody, &chatResp); err != nil {
		return nil, nil, fmt.Errorf("failed to parse response: %w", err)
	}
	if len(chatResp.Choices) == 0 {
		return nil, nil, fmt.Errorf("no response from API")
	}

	choice := chatResp.Choices[0]
	response := &ai.Response{
		Reply: choice.Message.Content,
		Usage: ai.Usage{
			InputTokens:  chatResp.Usage.PromptTokens,
			OutputTokens: chatResp.Usage.CompletionTokens,
			TotalTokens:  chatResp.Usage.TotalTokens,
		},
	}

	var rawToolCalls []map[string]any
	for _, tc := range choice.Message.ToolCalls {
		var input map[string]any

View on GitHub (pinned to 24529f1404)

Solutions

  1. Log respBody and the status code before unmarshalling to see the actual payload
  2. Verify BaseURL points at the Ollama OpenAI-compatible API (…/v1), not the root or native /api endpoint
  3. Upgrade Ollama to a version supporting the OpenAI-compatible chat completions endpoint
  4. Decode into json.RawMessage/map first and validate the shape before struct decoding

Example fix

// before
if err := json.Unmarshal(respBody, &chatResp); err != nil {
    return nil, nil, fmt.Errorf("failed to parse response: %w", err)
}
// after
if err := json.Unmarshal(respBody, &chatResp); err != nil {
    return nil, nil, fmt.Errorf("failed to parse response: %w: body=%.200s", err, string(respBody))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the endpoint returns JSON before calling
resp, err := http.Get(strings.TrimRight(baseURL, "/") + "/v1/models")
if err == nil {
    ct := resp.Header.Get("Content-Type")
    if !strings.Contains(ct, "application/json") {
        return fmt.Errorf("endpoint did not return JSON (content-type %s)", ct)
    }
}

Type guard

func looksLikeJSON(b []byte) bool {
    t := bytes.TrimSpace(b)
    return len(t) > 0 && (t[0] == '{' || t[0] == '[')
}

Try / catch

resp, err := provider.Generate(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse response") {
        // inspect raw body: proxy HTML? wrong endpoint? old Ollama?
    }
    return err
}

Prevention

When it happens

Trigger: json.Unmarshal(respBody, &chatResp) fails in callOpenAI (called from generateOpenAI) — non-JSON body (HTML from a proxy), truncated response, or Ollama version whose response shape differs from the struct.

Common situations: Hitting a non-Ollama endpoint (e.g. the base URL points to a web root returning HTML); an old Ollama version predating the OpenAI-compatibility layer; a reverse proxy error page; response body truncated by a proxy timeout.

Understand the failure class

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/5264679214e5c4b6. Report an issue: GitHub.