thanos-io/thanos · error
empty targetHealth
Error message
empty targetHealth
What it means
After successfully unquoting, TargetHealth.UnmarshalJSON rejects an empty string value because health must be one of the defined enum states (unknown, healthy, unhealthy). An empty targetHealth field in JSON triggers this error.
Solutions
- Provide a valid health value: "unknown", "healthy", or "unhealthy".
- If the source data may be empty, set the field to "unknown" before unmarshaling.
- Make the field a pointer (*TargetHealth) and skip unmarshal when absent instead of sending an empty string.
- Fix double-encoded values like "\"\"" to plain "unknown".
Example fix
// before
{"health": ""}
// after
{"health": "unknown"} Defensive patterns
Strategy: validation
Validate before calling
if health == "" { health = "unknown" } Type guard
func validTargetHealth(s string) bool { return s == "unknown" || s == "healthy" || s == "unhealthy" } Prevention
- Default missing health to "unknown" before serialization
- Make optional fields pointers so absence ≠ empty string
- Validate JSON fixtures against a schema
When it happens
Trigger: TargetHealth.UnmarshalJSON receives a JSON string that unquotes to "", e.g. "health": "" or "health": "\"\"" double-encoded.
Common situations: Empty DB/struct fields serialized to JSON by generic tooling; Prometheus targets data with missing health defaulted to empty string; hand-written fixtures.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- unknown targetHealth
- targetHealth: unquote
- unexpected downsampling resolution
- invalid targets parameter state=
- invalid rules parameter type=
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/4fa4cb3d2d424c1b.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/targets/targetspb/custom.go:39
}
}
func NewWarningTargetsResponse(warning error) *TargetsResponse {
return &TargetsResponse{
Result: &TargetsResponse_Warning{
Warning: warning.Error(),
},
}
}
func (x *TargetHealth) UnmarshalJSON(entry []byte) error {
fieldStr, err := strconv.Unquote(string(entry))
if err != nil {
return errors.Wrapf(err, "targetHealth: unquote %v", string(entry))
}
if fieldStr == "" {
return errors.New("empty targetHealth")
}
state, ok := TargetHealth_value[strings.ToUpper(fieldStr)]
if !ok {
return errors.Errorf("unknown targetHealth: %v", string(entry))
}
*x = TargetHealth(state)
return nil
}
func (x *TargetHealth) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(strings.ToLower(x.String()))), nil
}
func (x TargetHealth) Compare(y TargetHealth) int {
return int(x) - int(y)
}
View on GitHub (pinned to 35b8b99117)