{"record":{"id":"e8650b5121a8875b","repo":"vitessio/vitess","slug":"health-stats-is-not-valid-v","errorCode":null,"errorMessage":"health stats is not valid: %v","messagePattern":"health stats is not valid: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/discovery/tablet_health_check.go","lineNumber":170,"sourceCode":"\t\t\treturn nil\n\t\t}\n\t\tthc.Conn = conn\n\t\tthc.LastError = nil\n\t}\n\treturn thc.Conn\n}\n\n// processResponse reads one health check response, and updates health\nfunc (thc *tabletHealthCheck) processResponse(hc *HealthCheckImpl, shr *query.StreamHealthResponse) error {\n\tselect {\n\tcase <-thc.ctx.Done():\n\t\treturn thc.ctx.Err()\n\tdefault:\n\t}\n\n\t// Check for invalid data, better than panicking.\n\tif shr.Target == nil || shr.RealtimeStats == nil {\n\t\treturn fmt.Errorf(\"health stats is not valid: %v\", shr)\n\t}\n\n\t// an app-level error from tablet, force serving state.\n\tvar healthErr error\n\tserving := shr.Serving\n\tif shr.RealtimeStats.HealthError != \"\" {\n\t\thealthErr = fmt.Errorf(\"vttablet error: %v\", shr.RealtimeStats.HealthError)\n\t\tserving = false\n\t}\n\n\tif shr.TabletAlias != nil && !proto.Equal(shr.TabletAlias, thc.Tablet.Alias) {\n\t\t// TabletAlias change means that the host:port has been taken over by another tablet\n\t\t// We cancel / exit the healthcheck for this tablet right away\n\t\t// With the next topo refresh we will get a new tablet with the new host/port\n\t\treturn vterrors.New(vtrpc.Code_FAILED_PRECONDITION, fmt.Sprintf(\"health stats mismatch, tablet %+v alias does not match response alias %v\", thc.Tablet, shr.TabletAlias))\n\t}\n\n\tprevTarget := thc.Target","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/discovery/tablet_health_check.go#L152-L188","documentation":"processResponse validates every streaming health check response from a vttablet. If the StreamHealthResponse is missing its Target or RealtimeStats, the data is considered malformed and this error is returned instead of risking a nil-pointer panic, and the tablet's health state is not updated.","triggerScenarios":"A vttablet returns a StreamHealthResponse with a nil Target or nil RealtimeStats — typically an old/mismatched vttablet version, a tablet starting up, or a corrupted/partial RPC response.","commonSituations":"Mixed-version clusters (new gateways talking to older tablets); vttablet crash/restart mid-health-stream producing empty responses; proxy or networking layer truncating gRPC messages.","solutions":["Check the responding vttablet's version and upgrade it to match the gateway/cluster version.","Look at vttablet logs around the time of the malformed response for startup or crash issues.","Restart the affected vttablet if it persistently sends incomplete StreamHealthResponses.","Verify network path (no truncating proxies/LBs) between healthcheck and tablet."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func validHealthResponse(shr *querypb.StreamHealthResponse) bool {\n\treturn shr != nil && shr.Target != nil && shr.RealtimeStats != nil\n}","tryCatchPattern":null,"preventionTips":["Keep vttablet and gateway versions aligned across the cluster","Monitor for repeated malformed responses — indicates a broken tablet or proxy","Restart tablets that persistently emit incomplete StreamHealthResponses"],"tags":["healthcheck","grpc","version-compatibility"],"backgroundTag":"malformed-health-response","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}