{"record":{"id":"a8f499965b35c946","repo":"vitessio/vitess","slug":"marshal-primary-health-state-w","errorCode":null,"errorMessage":"marshal primary health state: %w","messagePattern":"marshal primary health state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtorc/inst/primary_health.go","lineNumber":277,"sourceCode":"\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) {\n\t\treturn deletePrimaryHealthState(tabletAlias)\n\t}\n\tpb := toProtoPrimaryHealthState(state)\n\tdata, err := prototext.Marshal(pb)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal primary health state: %w\", err)\n\t}\n\tquery := `REPLACE INTO primary_health (alias, health_state, last_updated) VALUES (?, ?, DATETIME('now'))`\n\t_, err = db.ExecVTOrc(query, tabletAlias, string(data))\n\treturn err\n}\n\n// deletePrimaryHealthState removes the persisted health window for a tablet alias.\n// It is safe to call repeatedly or with an empty alias.\nfunc deletePrimaryHealthState(tabletAlias string) error {\n\tif tabletAlias == \"\" {\n\t\treturn nil\n\t}\n\t_, err := db.ExecVTOrc(\"delete from primary_health where alias = ?\", tabletAlias)\n\treturn err\n}\n\n// toProtoPrimaryHealthState converts the in-memory health window to its protobuf form.\n// Timestamps are stored as Unix nanoseconds so ordering remains stable across reloads.","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtorc/inst/primary_health.go#L259-L295","documentation":"writePrimaryHealthState marshals the in-memory PrimaryHealthState to prototext before persisting it with REPLACE INTO primary_health. prototext.Marshal failure is unexpected for valid states but is wrapped and propagated so recordPrimaryHealthCheckAt (and its callers) surface it instead of silently skipping persistence.","triggerScenarios":"writePrimaryHealthState (called from recordPrimaryHealthCheckAt) marshaling a state that fails prototext encoding — practically only when the state/proto contains something invalid or a code change introduces an unmarshalable field.","commonSituations":"Custom builds or version-skew where toProtoPrimaryHealthState produces a message the linked proto cannot encode; rarely hit in stock Vitess.","solutions":["Inspect the wrapped cause (%w) — prototext.Marshal errors usually indicate a programming/proto-definition bug","Verify the vtorc binary and the vitess proto definitions come from the same version (no partial builds)","Check what state recordPrimaryHealthCheckAt produced; log it before marshal to identify the bad field","As a workaround, delete the health row so a fresh state window is built"],"exampleFix":"// before: error surfaces only at runtime\npb := toProtoPrimaryHealthState(state)\ndata, err := prototext.Marshal(pb)\n// after: guard against invalid state before marshal\nif state == nil {\n    return fmt.Errorf(\"marshal primary health state: nil state for %s\", tabletAlias)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := recordPrimaryHealthCheckAt(ctx, alias, now)\nif err != nil && strings.Contains(err.Error(), \"marshal primary health state\") {\n    // indicates a proto/code version mismatch; report and rebuild state\n    log.Error(\"primary health marshal failed\", slog.String(\"alias\", alias), slog.Any(\"error\", err))\n    _ = deletePrimaryHealthState(alias)\n}","preventionTips":["Build vtorc from a single consistent Vitess version (no partial proto updates)","Run make proto/codegen after any proto change so encode/decode stay in sync","Log the state before marshal in debug builds to catch invalid states early","Treat this error as a bug: stock Vitess states should always marshal cleanly"],"tags":["vtorc","serialization","prototext","database"],"backgroundTag":"proto-marshal-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}