{"record":{"id":"902899185ae06d7a","repo":"thanos-io/thanos","slug":"rule-recording-rule-unmarshal-v","errorCode":null,"errorMessage":"rule: recording rule unmarshal: %v","messagePattern":"rule: recording rule unmarshal: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/rules/rulespb/custom.go","lineNumber":220,"sourceCode":"\t\treturn \"\"\n\t}\n\n\treturn r.File + \";\" + r.Name\n}\n\nfunc (m *Rule) UnmarshalJSON(entry []byte) error {\n\tdecider := struct {\n\t\tType string `json:\"type\"`\n\t}{}\n\tif err := json.Unmarshal(entry, &decider); err != nil {\n\t\treturn errors.Wrapf(err, \"rule: type field unmarshal: %v\", string(entry))\n\t}\n\n\tswitch strings.ToLower(decider.Type) {\n\tcase \"recording\":\n\t\tr := &RecordingRule{}\n\t\tif err := json.Unmarshal(entry, r); err != nil {\n\t\t\treturn errors.Wrapf(err, \"rule: recording rule unmarshal: %v\", string(entry))\n\t\t}\n\n\t\tm.Result = &Rule_Recording{Recording: r}\n\tcase \"alerting\":\n\t\tr := &Alert{}\n\t\tif err := json.Unmarshal(entry, r); err != nil {\n\t\t\treturn errors.Wrapf(err, \"rule: alerting rule unmarshal: %v\", string(entry))\n\t\t}\n\n\t\tm.Result = &Rule_Alert{Alert: r}\n\tcase \"\":\n\t\treturn errors.Errorf(\"rule: no type field provided: %v\", string(entry))\n\tdefault:\n\t\treturn errors.Errorf(\"rule: unknown type field provided %s; %v\", decider.Type, string(entry))\n\t}\n\treturn nil\n}\n","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/rules/rulespb/custom.go#L202-L238","documentation":"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).","triggerScenarios":"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.","commonSituations":"YAML/JSON rules converted between Prometheus and Cortex formats; schema changes after upgrading rulespb; hand-edited rules with wrong field types.","solutions":["Compare the entry against the RecordingRule schema (record, expr string fields) and fix types/values","Regenerate the rules file from a validated Prometheus rules format","Check for version skew between the producer of the JSON and the current rulespb schema"],"exampleFix":"// before\n{\"type\": \"recording\", \"record\": 123, \"expr\": \"sum(rate(x[5m]))\"}\n// after\n{\"type\": \"recording\", \"record\": \"job:rate5m\", \"expr\": \"sum(rate(x[5m]))\"}","handlingStrategy":"validation","validationCode":"var probe struct {\n    Type   string `json:\"type\"`\n    Record string `json:\"record\"`\n    Expr   string `json:\"expr\"`\n}\nif err := json.Unmarshal(entry, &probe); err != nil || probe.Record == \"\" || probe.Expr == \"\" {\n    return fmt.Errorf(\"not a valid recording rule\")\n}","typeGuard":null,"tryCatchPattern":"if err := json.Unmarshal(entry, &rule); err != nil {\n    if strings.Contains(err.Error(), \"recording rule unmarshal\") {\n        log.Printf(\"bad recording rule entry: %s\", entry)\n    }\n    return err\n}","preventionTips":["Keep record and expr as strings in rule JSON","Validate rules against the rulespb schema in CI","Convert Prometheus YAML rules with a maintained converter"],"tags":["json","unmarshal","recording-rule"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}