thanos-io/thanos · error
error marshaling response
Error message
error marshaling response
What it means
API.Respond marshals the response struct with jsoniter (stdlib-compatible). If marshaling fails, it logs 'error marshaling response' and returns HTTP 500 with the marshal error text. This is an internal encoding failure, not a client input problem.
Solutions
- Check the logged err field to find which field fails to marshal.
- Sanitize numeric results: replace NaN/Inf with null before responding.
- Fix the handler's return type so it contains only JSON-encodable values.
Example fix
// before
return promql.Vector{{Point: promql.Point{T: ts, V: math.NaN()}}}, nil
// after
v := math.NaN()
if math.IsNaN(v) { v = 0 } // or encode as null
return promql.Vector{{Point: promql.Point{T: ts, V: v}}}, nil Defensive patterns
Strategy: fallback
Try / catch
resp = sanitizeForJSON(resp) // replace NaN/Inf with nil
b, err := json.Marshal(resp)
if err != nil {
level.Error(logger).Log("msg", "error marshaling response", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} Prevention
- Never return NaN/Inf floats in API handler results
- Keep handler return types JSON-encodable (no funcs, channels, cyclic refs)
- Add a test that marshals every endpoint's response shape
When it happens
Trigger: json.Marshal(resp) returns an error — e.g. resp.Data contains a value JSON cannot encode (NaN/Inf floats from query results, a channel/func field, or a custom MarshalJSON returning an error).
Common situations: Query endpoints returning NaN/Inf values in series data; a handler returning unencodable types (e.g. unmarshalable time formats or cyclic structures) in a custom API extension.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to get prometheus version
- received message larger than max
- Admin operations are disabled
- ID cannot be empty
- Action cannot be empty
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/37a5524b61ad5f68.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/api.go:287
w.Header().Set("Content-Type", "application/json")
if shouldNotCacheBecauseOfWarnings(warnings) {
w.Header().Set("Cache-Control", "no-store")
}
w.WriteHeader(http.StatusOK)
resp := &response{
Status: StatusSuccess,
Data: data,
}
for _, warn := range warnings {
resp.Warnings = append(resp.Warnings, warn.Error())
}
json := jsoniter.ConfigCompatibleWithStandardLibrary
b, err := json.Marshal(resp)
if err != nil {
level.Error(logger).Log("msg", "error marshaling response", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if n, err := w.Write(b); err != nil {
level.Error(logger).Log("msg", "error writing response", "bytesWritten", n, "err", err)
}
}
func RespondError(w http.ResponseWriter, apiErr *ApiError, data any, logger log.Logger) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-store")
var code int
switch apiErr.Typ {
case ErrorBadData:
code = http.StatusBadRequest
case ErrorExec:
code = 422View on GitHub (pinned to 35b8b99117)