{"record":{"id":"1c1495584d8291b7","repo":"thanos-io/thanos","slug":"rule-no-type-field-provided-v","errorCode":null,"errorMessage":"rule: no type field provided: %v","messagePattern":"rule: no type field provided: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/rules/rulespb/custom.go","lineNumber":232,"sourceCode":"\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\nfunc (m *Rule) MarshalJSON() ([]byte, error) {\n\tif r := m.GetRecording(); r != nil {\n\t\treturn json.Marshal(struct {\n\t\t\t*RecordingRule\n\t\t\tType string `json:\"type\"`\n\t\t}{\n\t\t\tRecordingRule: r,\n\t\t\tType:          RuleRecordingType,\n\t\t})\n\t}\n\ta := m.GetAlert()\n\tif a.Alerts == nil {","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/rules/rulespb/custom.go#L214-L250","documentation":"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.","triggerScenarios":"Decoding rule entries that omit \"type\" — e.g. rules JSON written by hand or by tools predating the typed-rule schema.","commonSituations":"Old rule files from before the type field was introduced; templates that skip the type key; manually stripping fields when converting formats.","solutions":["Add \"type\": \"alerting\" or \"type\": \"recording\" to each rule entry","Regenerate the rules file with a current exporter that includes the type field","Add a pre-upload validation step that asserts every rule has a non-empty type"],"exampleFix":"// before\n{\"name\": \"HighErrors\", \"expr\": \"up == 0\"}\n// after\n{\"type\": \"alerting\", \"name\": \"HighErrors\", \"expr\": \"up == 0\"}","handlingStrategy":"validation","validationCode":"var decider struct {\n    Type string `json:\"type\"`\n}\nif err := json.Unmarshal(entry, &decider); err != nil || decider.Type == \"\" {\n    return fmt.Errorf(\"rule entry must declare a type\")\n}","typeGuard":"func hasRuleType(entry []byte) bool {\n    var d struct { Type string `json:\"type\"` }\n    return json.Unmarshal(entry, &d) == nil && d.Type != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always emit the type field when generating rule JSON","Upgrade legacy rule files that predate the typed schema","Add a schema check to the rules upload pipeline"],"tags":["json","schema","rules"],"backgroundTag":"schema-validation-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"}