{"record":{"id":"1357f1edd35ae80f","repo":"vitessio/vitess","slug":"can-t-parse-binlog-event-invalid-data-v","errorCode":null,"errorMessage":"can't parse binlog event, invalid data: %#v","messagePattern":"can't parse binlog event, invalid data: %#v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/binlog/binlog_streamer.go","lineNumber":314,"sourceCode":"\t\tvar ok bool\n\n\t\tselect {\n\t\tcase ev, ok = <-events:\n\t\t\tif !ok {\n\t\t\t\t// events channel has been closed, which means the connection died.\n\t\t\t\tlog.Info(\"reached end of binlog event stream\")\n\t\t\t\treturn pos, ErrServerEOF\n\t\t\t}\n\t\tcase err = <-errs:\n\t\t\treturn pos, err\n\t\tcase <-ctx.Done():\n\t\t\tlog.Info(\"stopping early due to binlog Streamer service shutdown or client disconnect\")\n\t\t\treturn pos, ctx.Err()\n\t\t}\n\n\t\t// Validate the buffer before reading fields from it.\n\t\tif !ev.IsValid() {\n\t\t\treturn pos, fmt.Errorf(\"can't parse binlog event, invalid data: %#v\", ev)\n\t\t}\n\n\t\t// We need to keep checking for FORMAT_DESCRIPTION_EVENT even after we've\n\t\t// seen one, because another one might come along (e.g. on log rotate due to\n\t\t// binlog settings change) that changes the format.\n\t\tif ev.IsFormatDescription() {\n\t\t\tformat, err = ev.Format()\n\t\t\tif err != nil {\n\t\t\t\treturn pos, fmt.Errorf(\"can't parse FORMAT_DESCRIPTION_EVENT: %v, event data: %#v\", err, ev)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// We can't parse anything until we get a FORMAT_DESCRIPTION_EVENT that\n\t\t// tells us the size of the event header.\n\t\tif format.IsZero() {\n\t\t\t// The only thing that should come before the FORMAT_DESCRIPTION_EVENT\n\t\t\t// is a fake ROTATE_EVENT, which the primary sends to tell us the name","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/binlog/binlog_streamer.go#L296-L332","documentation":"parseEvents validates every raw binlog event buffer with ev.IsValid() before decoding fields. If the event's byte buffer is too short or malformed to even contain a valid header, the streamer aborts with this message including the raw event dump. This indicates corrupt or truncated binlog data from the server.","triggerScenarios":"During Stream/parseEvents, the events channel delivers a mysql.BinlogEvent whose underlying buffer fails IsValid() — e.g. an event shorter than the binlog header, or corrupted packet data from the binlog dump.","commonSituations":"Binlog files corrupted on disk; a buggy/proxying layer truncating binlog dump packets; reading binlogs from a non-MySQL or patched server emitting malformed events; memory/network corruption.","solutions":["Verify the server's binlog files with mysqlbinlog on the affected log file to confirm corruption","Check for proxies or packet mangling between vttablet and MySQL; bypass them","Fail over to a healthy replica whose binlogs are intact and restart the stream from the last good GTID position","Report to Vitess if it reproduces consistently against a supported MySQL version (possible parser bug)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := streamer.Stream(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"invalid data\") {\n\t\t// corrupt event: verify binlog with mysqlbinlog, fail over, restart from good GTID\n\t}\n}","preventionTips":["Keep MySQL and network path between tablet and server clean of packet-mangling proxies","Monitor binlog file integrity","Use supported MySQL versions","Fail over promptly at signs of binlog corruption"],"tags":["binlog","corruption","parsing"],"backgroundTag":"corrupt-binlog-event","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}