micro/go-micro · error

failed to parse response: %w

Error message

failed to parse response: %w

What it means

The library received a 2xx response body but json.Unmarshal could not decode it into the expected chatCompletion response struct. This means the payload was not valid JSON or did not match the expected schema (e.g. choices was an object instead of an array).

Source

Thrown at ai/openai/openai.go:349

			CompletionTokens int `json:"completion_tokens"`
			TotalTokens      int `json:"total_tokens"`
		} `json:"usage"`
		Choices []struct {
			Message struct {
				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},
	}

	// Extract tool calls
	for _, tc := range choice.Message.ToolCalls {
		var input map[string]any
		if err := json.Unmarshal([]byte(tc.Function.Arguments), &input); err != nil {
			input = map[string]any{}
		}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Print/log respBody on this error to see what the server actually returned
  2. Confirm BaseURL points at an OpenAI-compatible endpoint (path /v1/chat/completions) and not a UI page
  3. Disable/fix proxies or gateways that inject HTML into responses
  4. If using a compatible-but-different provider, check its response schema against the library's struct

Example fix

// before
apiURL := cfg.OpenAIBaseURL // accidentally https://internal-portal/login
// after
apiURL := "https://api.openai.com" // real OpenAI-compatible API host
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.BaseURL)
if err != nil || !strings.HasSuffix(u.Path, "/v1") && u.Path != "" {
    // ensure it points at an OpenAI-compatible API root, not a web UI
}
// sanity ping
resp, err := http.Get(cfg.BaseURL + "/v1/models")
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
    return fmt.Errorf("endpoint does not return JSON (Content-Type: %s)", ct)
}

Try / catch

resp, err := provider.Generate(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to parse response") {
    log.Printf("non-JSON payload from endpoint; check BaseURL/proxy: %v", err)
    return err
}

Prevention

When it happens

Trigger: callAPI got httpResp.StatusCode == 200 but respBody is not JSON or has unexpected shape: an HTML error/login page from a misconfigured proxy, a truncated body, or an OpenAI-compatible server returning a different schema.

Common situations: Pointing BaseURL at a non-OpenAI service or gateway that returns HTML on success, a gateway stripping/chunk-encoding the body incorrectly, using an OpenAI-compatible provider (e.g. self-hosted) whose response schema diverges.

Understand the failure class

Related errors


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