thanos-io/thanos · error
rule : unsupported type %T
Error message
rule %q: unsupported type %T
What it means
toProto converts a rule to protobuf; when the rule's concrete type matches none of the supported cases (AlertingRule, RecordingRule), it panics deliberately. The HTTP API recovers the panic, so it surfaces as a recovered internal error, not a normal error return.
Solutions
- Upgrade Thanos to a version supporting the rule type (or align Prometheus dependency versions)
- Identify the unexpected %T printed in the panic message and check which code created it
- If you embed the rules manager, ensure only AlertingRule/RecordingRule enter groups
- Recover at API boundary — this is already done via panic+recover by design
Example fix
// before
case *rules.AlertingRule: ...; default: panic(...)
// after
case *rules.RecordingRule: ...
case *rules.AlertingRule: ...
default:
level.Error(logger).Log("msg", "unsupported rule type", "type", fmt.Sprintf("%T", rule)) Defensive patterns
Strategy: type-guard
Validate before calling
switch rule.(type) {
case *rules.AlertingRule, *rules.RecordingRule:
// safe to convert
default:
return fmt.Errorf("rule %q: unsupported type %T", rule.Name(), rule)
} Type guard
func isConvertibleRule(r rules.Rule) bool {
switch r.(type) {
case *rules.AlertingRule, *rules.RecordingRule:
return true
default:
return false
}
} Try / catch
func safeToProto(...) (ret []*rulespb.Rule, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("toProto panicked: %v", r)
}
}()
ret = toProto(...)
return
} Prevention
- Keep the Prometheus rules library version aligned with Thanos's supported types
- Never inject custom or mock rule implementations into production managers
- Cover both rule kinds in conversion unit tests
When it happens
Trigger: A rules.Group or RulesStore contains a rules.Rule implementation that is neither *rules.AlertingRule nor *rules.RecordingRule — typically a new rule type added in Prometheus/Thanos without updating toProto, or a mock rule leaking into production paths.
Common situations: Version mismatch between the Prometheus rules library and Thanos; custom/test rule implementations; upstream Prometheus added a new rule kind.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- BUG: localAsyncWriter.RemoteWrite called without…
- http.Error(w, err.Error(), http.StatusInternalServerError)
- retrieving rule files failed. Ignoring file. pattern
- reloading rules failed
- failed to convert matchers
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/231432366b5b1b7b.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/rules/manager.go:91
EvaluationDurationSeconds: rule.GetEvaluationDuration().Seconds(),
// UTC needed due to https://github.com/gogo/protobuf/issues/519.
LastEvaluation: rule.GetEvaluationTimestamp().UTC(),
}}})
case *rules.RecordingRule:
ret.Rules = append(ret.Rules, &rulespb.Rule{
Result: &rulespb.Rule_Recording{Recording: &rulespb.RecordingRule{
Name: rule.Name(),
Query: rule.Query().String(),
Labels: labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(rule.Labels())},
Health: string(rule.Health()),
LastError: lastError,
EvaluationDurationSeconds: rule.GetEvaluationDuration().Seconds(),
// UTC needed due to https://github.com/gogo/protobuf/issues/519.
LastEvaluation: rule.GetEvaluationTimestamp().UTC(),
}}})
default:
// We cannot do much, let's panic, API will recover.
panic(fmt.Sprintf("rule %q: unsupported type %T", r.Name(), rule))
}
}
return ret
}
func ActiveAlertsToProto(s storepb.PartialResponseStrategy, a *rules.AlertingRule) []*rulespb.AlertInstance {
active := a.ActiveAlerts()
ret := make([]*rulespb.AlertInstance, len(active))
for i, ruleAlert := range active {
// UTC needed due to https://github.com/gogo/protobuf/issues/519.
activeAt := ruleAlert.ActiveAt.UTC()
ret[i] = &rulespb.AlertInstance{
PartialResponseStrategy: s,
Labels: labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(ruleAlert.Labels)},
Annotations: labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(ruleAlert.Annotations)},
State: rulespb.AlertState(ruleAlert.State),
ActiveAt: &activeAt,
Value: strconv.FormatFloat(ruleAlert.Value, 'e', -1, 64),View on GitHub (pinned to 35b8b99117)