{"record":{"id":"e64e3bd4a6266e83","repo":"vitessio/vitess","slug":"unmarshal-primary-health-state-w","errorCode":null,"errorMessage":"unmarshal primary health state: %w","messagePattern":"unmarshal primary health state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtorc/inst/primary_health.go","lineNumber":253,"sourceCode":"// without immediately triggering recovery.\nfunc primaryHealthWindow() time.Duration {\n\treturn topo.RemoteOperationTimeout * 5\n}\n\n// readPrimaryHealthState loads the persisted health window for a tablet alias.\n// It returns nil when no row exists, and wraps any unmarshaling errors with\n// context to help identify corrupt or incompatible state.\nfunc readPrimaryHealthState(tabletAlias string) (*primaryHealthState, error) {\n\tquery := \"select health_state from primary_health where alias = ?\"\n\tvar state *primaryHealthState\n\terr := db.QueryVTOrc(query, sqlutils.Args(tabletAlias), func(row sqlutils.RowMap) error {\n\t\tvalue := row.GetString(\"health_state\")\n\t\tif value == \"\" {\n\t\t\treturn nil\n\t\t}\n\t\tpb := &vtorcdata.PrimaryHealthState{}\n\t\tif err := prototext.Unmarshal([]byte(value), pb); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshal primary health state: %w\", err)\n\t\t}\n\t\tstate = fromProtoPrimaryHealthState(pb)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn state, nil\n}\n\n// writePrimaryHealthState persists the current health window for a tablet alias.\n// It is a no-op for empty aliases or nil state, and it deletes the row if the\n// state is already evictable.\nfunc writePrimaryHealthState(tabletAlias string, state *primaryHealthState) error {\n\tif tabletAlias == \"\" || state == nil {\n\t\treturn nil\n\t}\n\tif shouldEvictPrimaryHealthWindow(state) {","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtorc/inst/primary_health.go#L235-L271","documentation":"vtorc persists the primary health window as prototext in the primary_health table. When reading it back, prototext.Unmarshal failed on the stored string, so the stored state is corrupt or written by an incompatible schema/version. The scan error is wrapped with context.","triggerScenarios":"Reading the health_state column (GetString(\"health_state\")) containing a non-empty value that is not valid prototext for vtorcdata.PrimaryHealthState — e.g. truncated row, manual edits, or format changed between Vitess versions.","commonSituations":"Upgrading/downgrading Vitess where the PrimaryHealthState proto changed, DBA hand-editing the primary_health table, disk/storage corruption, or an aborted write leaving partial data.","solutions":["Inspect the offending row: SELECT alias, health_state FROM primary_health WHERE alias = '<tablet>'","Delete the corrupt row (DELETE FROM primary_health WHERE alias=...) — vtorc will rebuild the window from subsequent checks","Check for a version mismatch: if you recently upgraded vtorc, ensure the table contents were written by a compatible version","Restart vtorc after cleanup; the state repopulates automatically as health checks are recorded"],"exampleFix":"-- before: corrupt stored state causes unmarshal failure\nSELECT health_state FROM primary_health WHERE alias='zone1-0000000100';  -- garbage\n-- after: reset it\nDELETE FROM primary_health WHERE alias='zone1-0000000100';","handlingStrategy":"fallback","validationCode":"-- Detect corrupt rows before they break vtorc\nSELECT alias, health_state FROM primary_health\nWHERE health_state IS NOT NULL AND health_state != ''\n  AND health_state NOT LIKE 'alias:%';  -- sanity heuristic: prototext of PrimaryHealthState starts with field names","typeGuard":null,"tryCatchPattern":"state, err := readPrimaryHealthState(ctx, alias)\nif err != nil {\n    // corrupt/unreadable stored state: fall back to a fresh window\n    log.Warn(\"primary health state unreadable, resetting\", slog.Any(\"error\", err))\n    _ = deletePrimaryHealthState(alias)\n    state = newPrimaryHealthState()\n}","preventionTips":["Never hand-edit the primary_health table","Take clean upgrades: don't run mixed Vitess versions writing the same table","Back up and reset the table if a version changed the PrimaryHealthState proto","Alert on unmarshal errors in vtorc logs — they indicate storage corruption"],"tags":["vtorc","serialization","prototext","database"],"backgroundTag":"proto-unmarshal-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}