{"record":{"id":"0e4227086476fca7","repo":"thanos-io/thanos","slug":"rule-type-field-unmarshal-v","errorCode":null,"errorMessage":"rule: type field unmarshal: %v","messagePattern":"rule: type field unmarshal: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/rules/rulespb/custom.go","lineNumber":213,"sourceCode":"\treturn strings.Compare(r1.Key(), r2.Key())\n}\n\n// Key returns the group key similar resembling Prometheus logic.\n// See https://github.com/prometheus/prometheus/blob/869f1bc587e667b79721852d5badd9f70a39fc3f/rules/manager.go#L1062-L1065\nfunc (r *RuleGroup) Key() string {\n\tif r == nil {\n\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 \"\":","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/rules/rulespb/custom.go#L195-L231","documentation":"Rule.UnmarshalJSON first peeks at the JSON 'type' field to decide whether the entry is a recording rule or an alert. If the raw bytes are not valid JSON at all, the json.Unmarshal error is wrapped as 'rule: type field unmarshal' including the offending entry. It means the rule entry is malformed JSON before type dispatch even happens.","triggerScenarios":"Feeding Rule entries from a rules file, API payload, or object store that contain invalid JSON (truncated file, trailing commas, concatenated JSON objects).","commonSituations":"Corrupted or partially written rules files in config storage; copying rules between systems with quoting damage; templating tools emitting invalid JSON.","solutions":["Validate the rules file with jq or a JSON linter to find the malformed entry","Fix quoting/escaping around the rule entry (especially when generated via templates or shell)","Re-export or re-upload the rules from source"],"exampleFix":"// before (invalid JSON)\n{\"type\": \"alerting\", \"alert\": \"HighErrors\", \"expr\": \"rate(x[5m]) > 1,}\n// after\n{\"type\": \"alerting\", \"alert\": \"HighErrors\", \"expr\": \"rate(x[5m]) > 1\"}","handlingStrategy":"validation","validationCode":"if !json.Valid(entry) {\n    return fmt.Errorf(\"invalid rule JSON\")\n}","typeGuard":null,"tryCatchPattern":"var m rulespb.Rule\nif err := json.Unmarshal(entry, &m); err != nil {\n    var serr *json.SyntaxError\n    if errors.As(err, &serr) {\n        log.Printf(\"JSON syntax error at offset %d: %v\", serr.Offset, serr)\n    }\n    return err\n}","preventionTips":["Run jq . over rules files before uploading","Avoid generating rules JSON via shell string interpolation","Write rules files atomically to avoid truncated reads"],"tags":["json","unmarshal","rules"],"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"}