micro/go-micro · error
${rsp.Status}: ${body} (dynamic HTTP status and body)
Error message
${rsp.Status}: ${body} (dynamic HTTP status and body) What it means
When an HTTP response's status code is anything other than 200 OK, Recv reads the whole body and returns an error containing '<status string>: <body>'. The error message is dynamic: the transport surfaces the upstream HTTP status and response body directly as the error text, so non-OK responses never reach your Message.
Source
Thrown at transport/http_client.go:169
rsp, err := http.ReadResponse(h.buff, req)
if err != nil {
return err
}
defer func() {
if err2 := rsp.Body.Close(); err2 != nil {
err = errors.Wrap(err2, "failed to close body")
}
}()
b, err := io.ReadAll(rsp.Body)
if err != nil {
return err
}
if rsp.StatusCode != http.StatusOK {
return errors.New(rsp.Status + ": " + string(b))
}
msg.Body = b
if msg.Header == nil {
msg.Header = make(map[string]string, len(rsp.Header))
}
for k, v := range rsp.Header {
if len(v) > 0 {
msg.Header[k] = v[0]
} else {
msg.Header[k] = ""
}
}
return nil
}View on GitHub (pinned to 24529f1404)
Solutions
- Log err.Error() — it embeds the HTTP status and the server's error body; fix the root cause the status indicates (auth, path, payload)
- On the client side, match the status prefix (e.g. strings.HasPrefix(err.Error(), "401")) if you need to branch, or prefer the socket/stream API that exposes headers
- Fix the server side so healthy requests return 200; add health checks/retries for transient 5xx
Example fix
// before
if err := client.Recv(msg); err != nil { return err } // "401 Unauthorized: {\"error\":...}" opaque
// after
if err := client.Recv(msg); err != nil {
if strings.HasPrefix(err.Error(), "401") { return ErrUnauthorized }
return err
} Defensive patterns
Strategy: try-catch
Try / catch
if err := client.Recv(msg); err != nil {
for _, code := range []string{"401","403","404","500"} {
if strings.HasPrefix(err.Error(), code) { /* handle status */ }
}
return err
} Prevention
- Log the full error text — it contains status and server body
- Prefer checking endpoint health before calls in tests
- Retry only 5xx; surface 4xx to the caller
When it happens
Trigger: Any Recv over a plain (non-stream) request where the server replies 4xx/5xx — auth failures (401/403), not found (404), validation errors (400), or backend crashes (500).
Common situations: Calling a service whose endpoint moved (404), expired credentials (401), or a downstream service returning JSON error bodies that end up concatenated into the Go error string; parsing code that expects msg.Body gets nothing because the error path fired first.
Related errors
- failed request
- message passed in is nil
- stream API error (%s): %s
- API error (%s): %s
- failed to close body
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/d9f19b203074fec4.
Report an issue: GitHub.