micro/go-micro · error
failed to parse response: %w
Error message
failed to parse response: %w
What it means
callAPI wraps the error from json.Unmarshal when the HTTP 200 body cannot be decoded into the expected chat-completion response struct. It means the API returned a 200 whose JSON shape does not match the expected {choices:[{message:{...}}]} schema. The library throws it to surface the decode failure with the underlying *json.UnmarshalTypeError or *json.SyntaxError attached.
Source
Thrown at ai/atlascloud/atlascloud.go:466
retryAfter := time.Duration(0)
var retryErr interface{ RetryAfter() time.Duration }
if errors.As(ai.NewHTTPError(httpResp, respBody), &retryErr) {
retryAfter = retryErr.RetryAfter()
}
return nil, nil, &atlascloudAPIError{Status: httpResp.Status, Code: httpResp.StatusCode, Retry: retryAfter, Phase: phase, Summary: atlascloudRequestSummary(req), Body: string(respBody)}
}
var chatResp struct {
Choices []struct {
Message struct {
Content string `json:"content"`
ToolCalls []atlasToolCall `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,
}
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{}
}
response.ToolCalls = append(response.ToolCalls, ai.ToolCall{
ID: tc.ID,View on GitHub (pinned to 24529f1404)
Solutions
- Log string(respBody) on this error to see what the API actually returned and compare against the expected chat response schema.
- Confirm the API version/model endpoint matches what this provider version expects; pin or update the provider code if AtlasCloud changed its schema.
- Check for intermediaries returning HTML (proxy auth pages) by inspecting Content-Type of the response.
- Capture the error from io.ReadAll instead of discarding it so truncated bodies are detected before unmarshal.
Example fix
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
Type guard
func isValidChatResponse(b []byte) bool {
var probe struct {
Choices []json.RawMessage `json:"choices"`
}
return json.Unmarshal(b, &probe) == nil
} Try / catch
resp, err := provider.Generate(ctx, req)
if err != nil {
if strings.Contains(err.Error(), "failed to parse response") {
var uerr *json.UnmarshalTypeError
if errors.As(err, &uerr) {
log.Printf("schema mismatch at %s: %v", uerr.Field, uerr)
}
}
return err
} Prevention
- Log the raw response body whenever parsing fails to spot schema drift early.
- Pin the provider API version in BaseURL where supported.
- Check Content-Type of responses to detect HTML from proxies/WAFs.
- Keep the provider library updated when the AtlasCloud API changes.
When it happens
Trigger: json.Unmarshal(respBody, &chatResp) returns an error: the body is empty, truncated, HTML (e.g. a proxy/login page), or field types diverge from the struct (e.g. content returned as an array or null where a string is expected).
Common situations: Provider changed its response schema after an API version update; an intermediary (gateway, WAF, captive portal) returned HTML with status 200; response body was read incompletely because io.ReadAll's error was ignored; model returned tool_calls in an unexpected format.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse submit response: %w
- changeset is nil
- unsupported format
- API request failed: %w
- no response from API
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/62769d7ef73410a9.
Report an issue: GitHub.