thanos-io/thanos · error

rule: recording rule unmarshal

Error message

rule: recording rule unmarshal: %v

What it means

When Rule.UnmarshalJSON sees type == "recording", it unmarshals the same entry into a RecordingRule; failure is wrapped as 'rule: recording rule unmarshal' with the raw entry. The type field was valid but the recording-rule payload is missing or mistyping required fields (e.g. record/expr not strings).

Solutions

  1. Compare the entry against the RecordingRule schema (record, expr string fields) and fix types/values
  2. Regenerate the rules file from a validated Prometheus rules format
  3. Check for version skew between the producer of the JSON and the current rulespb schema

Example fix

// before
{"type": "recording", "record": 123, "expr": "sum(rate(x[5m]))"}
// after
{"type": "recording", "record": "job:rate5m", "expr": "sum(rate(x[5m]))"}
Defensive patterns

Strategy: validation

Validate before calling

var probe struct {
    Type   string `json:"type"`
    Record string `json:"record"`
    Expr   string `json:"expr"`
}
if err := json.Unmarshal(entry, &probe); err != nil || probe.Record == "" || probe.Expr == "" {
    return fmt.Errorf("not a valid recording rule")
}

Try / catch

if err := json.Unmarshal(entry, &rule); err != nil {
    if strings.Contains(err.Error(), "recording rule unmarshal") {
        log.Printf("bad recording rule entry: %s", entry)
    }
    return err
}

Prevention

When it happens

Trigger: A rule entry with "type": "recording" whose fields don't match the RecordingRule JSON schema — wrong types (record as number), unknown incompatible shape, or JSON valid for one schema version but not another.

Common situations: YAML/JSON rules converted between Prometheus and Cortex formats; schema changes after upgrading rulespb; hand-edited rules with wrong field types.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

		return ""
	}

	return r.File + ";" + r.Name
}

func (m *Rule) UnmarshalJSON(entry []byte) error {
	decider := struct {
		Type string `json:"type"`
	}{}
	if err := json.Unmarshal(entry, &decider); err != nil {
		return errors.Wrapf(err, "rule: type field unmarshal: %v", string(entry))
	}

	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
}

View on GitHub (pinned to 35b8b99117)