{"record":{"id":"6a9ca2f3944273fa","repo":"vitessio/vitess","slug":"error-unmarshaling-query-rules-v-original-data","errorCode":null,"errorMessage":"error unmarshaling query rules: %v, original data '%s' version %v","messagePattern":"error unmarshaling query rules: (.+?), original data '(.+?)' version (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/customrule/topocustomrule/topocustomrule.go","lineNumber":134,"sourceCode":"\t\t\tlog.Warn(fmt.Sprintf(\"Sleeping for %v before trying again\", sleepDuringTopoFailure))\n\t\t\ttime.Sleep(sleepDuringTopoFailure)\n\t\t}\n\t}()\n}\n\nfunc (cr *topoCustomRule) stop() {\n\tcr.mu.Lock()\n\tif cr.cancel != nil {\n\t\tcr.cancel()\n\t}\n\tcr.stopped = true\n\tcr.mu.Unlock()\n}\n\nfunc (cr *topoCustomRule) apply(wd *topo.WatchData) error {\n\tqrs := rules.New()\n\tif err := qrs.UnmarshalJSON(wd.Contents); err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling query rules: %v, original data '%s' version %v\", err, wd.Contents, wd.Version)\n\t}\n\n\tif !reflect.DeepEqual(cr.qrs, qrs) {\n\t\tcr.qrs = qrs.Copy()\n\t\tcr.qsc.SetQueryRules(topoCustomRuleSource, qrs)\n\t\tlog.Info(fmt.Sprintf(\"Custom rule version %v fetched from topo and applied to vttablet\", wd.Version))\n\t}\n\n\treturn nil\n}\n\nfunc (cr *topoCustomRule) oneWatch() error {\n\tdefer func() {\n\t\t// Whatever happens, cancel() won't be valid after this function exits.\n\t\tcr.mu.Lock()\n\t\tcr.cancel = nil\n\t\tcr.mu.Unlock()\n\t}()","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/customrule/topocustomrule/topocustomrule.go#L116-L152","documentation":"topocustomrule watches a topo path holding QueryRules JSON for the tablet's query service. When a watch event fires, apply() unmarshals the watched contents into rules.Rules; if the stored JSON is not valid query-rules JSON, the watch update is rejected with this error carrying the unmarshal error, the raw data, and the topo version — leaving the previous rules in effect.","triggerScenarios":"oneWatch receives a WatchData whose Contents fail rules.Rules.UnmarshalJSON — i.e. the value written to the topo custom-rule path is malformed JSON, a wrong schema, or a truncated write.","commonSituations":"Operator wrote hand-edited JSON to the custom rules topo file with a syntax error; wrote the right JSON under the wrong path so the schema doesn't match; a partial topo write during a network blip.","solutions":["Fix the JSON stored at the topo custom rules path to be a valid QueryRules document (validate with jq or rules.New().UnmarshalJSON in a test)","Re-write the file via vtctldclient so a fresh version triggers a new watch event and the rules get applied","Check the 'original data' and 'version' embedded in the error to find the exact topo entry to correct","Confirm you are editing the path this vttablet watches (topoCustomRuleSource) and not another cell's copy"],"exampleFix":"// topo file before (invalid)\n{\"rules\": [{\"match\": \"SELECT *\"}]}\n// topo file after (valid QueryRules)\n{\"rules\": [{\"description\": \"block\", \"match\": \"SELECT .* FROM t\", \"action\": \"FAIL\"}]}","handlingStrategy":"validation","validationCode":"var probe rules.Rules\nif err := json.Unmarshal(contents, &probe); err != nil {\n    return fmt.Errorf(\"custom rules JSON invalid: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := applyRules(wd); err != nil && strings.Contains(err.Error(), \"error unmarshaling query rules\") {\n    log.Error(\"bad topo custom rules; keeping previous rules\", slog.Any(\"error\", err))\n}","preventionTips":["Validate JSON with jq before writing to the topo path","Use vtctldclient to write custom rules instead of hand-editing topo","Confirm version parity: apply once with UnmarshalJSON in CI before rollout"],"tags":["vttablet","topo","query-rules","json"],"backgroundTag":"invalid-query-rules-json","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}