thanos-io/thanos · error

rule: no type field provided

Error message

rule: no type field provided: %v

What it means

Rule.UnmarshalJSON requires a 'type' field to choose between recording and alerting rule shapes. If the JSON is valid but type is an empty string, it errors with 'rule: no type field provided' plus the raw entry. Every rule entry must declare its type.

Solutions

  1. Add "type": "alerting" or "type": "recording" to each rule entry
  2. Regenerate the rules file with a current exporter that includes the type field
  3. Add a pre-upload validation step that asserts every rule has a non-empty type

Example fix

// before
{"name": "HighErrors", "expr": "up == 0"}
// after
{"type": "alerting", "name": "HighErrors", "expr": "up == 0"}
Defensive patterns

Strategy: validation

Validate before calling

var decider struct {
    Type string `json:"type"`
}
if err := json.Unmarshal(entry, &decider); err != nil || decider.Type == "" {
    return fmt.Errorf("rule entry must declare a type")
}

Type guard

func hasRuleType(entry []byte) bool {
    var d struct { Type string `json:"type"` }
    return json.Unmarshal(entry, &d) == nil && d.Type != ""
}

Prevention

When it happens

Trigger: Decoding rule entries that omit "type" — e.g. rules JSON written by hand or by tools predating the typed-rule schema.

Common situations: Old rule files from before the type field was introduced; templates that skip the type key; manually stripping fields when converting formats.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/1c1495584d8291b7. Report an issue: GitHub.

Appendix: source

Thrown at pkg/rules/rulespb/custom.go:232

	}

	switch strings.ToLower(decider.Type) {
	case "recording":
		r := &RecordingRule{}
		if err := json.Unmarshal(entry, r); err != nil {
			return errors.Wrapf(err, "rule: recording rule unmarshal: %v", string(entry))
		}

		m.Result = &Rule_Recording{Recording: r}
	case "alerting":
		r := &Alert{}
		if err := json.Unmarshal(entry, r); err != nil {
			return errors.Wrapf(err, "rule: alerting rule unmarshal: %v", string(entry))
		}

		m.Result = &Rule_Alert{Alert: r}
	case "":
		return errors.Errorf("rule: no type field provided: %v", string(entry))
	default:
		return errors.Errorf("rule: unknown type field provided %s; %v", decider.Type, string(entry))
	}
	return nil
}

func (m *Rule) MarshalJSON() ([]byte, error) {
	if r := m.GetRecording(); r != nil {
		return json.Marshal(struct {
			*RecordingRule
			Type string `json:"type"`
		}{
			RecordingRule: r,
			Type:          RuleRecordingType,
		})
	}
	a := m.GetAlert()
	if a.Alerts == nil {

View on GitHub (pinned to 35b8b99117)