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

  1. Upgrade Thanos to a version supporting the rule type (or align Prometheus dependency versions)
  2. Identify the unexpected %T printed in the panic message and check which code created it
  3. If you embed the rules manager, ensure only AlertingRule/RecordingRule enter groups
  4. 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

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


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)