{"record":{"id":"329bee371ba3b9af","repo":"vitessio/vitess","slug":"can-t-parse-format-description-event-v-event-da-329bee","errorCode":null,"errorMessage":"can't parse FORMAT_DESCRIPTION_EVENT: %v, event data: %#v","messagePattern":"can't parse FORMAT_DESCRIPTION_EVENT: (.+?), event data: %#v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"go/vt/vttablet/tabletserver/vstreamer/vstreamer.go","lineNumber":533,"sourceCode":"\n// parseEvent parses an event from the binlog and converts it to a list of VEvents.\n// The bufferAndTransmit function must be passed if the event is a TransactionPayloadEvent\n// as for larger payloads (> ZstdInMemoryDecompressorMaxSize) the internal events need\n// to be streamed directly here in order to avoid holding the entire payload's contents,\n// which can be 10s or even 100s of GiBs, all in memory.\nfunc (vs *vstreamer) parseEvent(ev mysql.BinlogEvent, bufferAndTransmit func(vevent *binlogdatapb.VEvent) error) ([]*binlogdatapb.VEvent, error) {\n\tif !ev.IsValid() {\n\t\treturn nil, fmt.Errorf(\"can't parse binlog event: invalid data: %#v\", ev)\n\t}\n\n\t// We need to keep checking for FORMAT_DESCRIPTION_EVENT even after we've\n\t// seen one, because another one might come along (e.g. on log rotate due to\n\t// binlog settings change) that changes the format.\n\tif ev.IsFormatDescription() {\n\t\tvar err error\n\t\tvs.format, err = ev.Format()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"can't parse FORMAT_DESCRIPTION_EVENT: %v, event data: %#v\", err, ev)\n\t\t}\n\t\tvs.eventGTID = nil\n\t\treturn nil, nil\n\t}\n\n\t// We can't parse anything until we get a FORMAT_DESCRIPTION_EVENT that\n\t// tells us the size of the event header.\n\tif vs.format.IsZero() {\n\t\t// The only thing that should come before the FORMAT_DESCRIPTION_EVENT\n\t\t// is a fake ROTATE_EVENT, which the primary sends to tell us the name\n\t\t// of the current log file.\n\t\tif ev.IsRotate() {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"got a real event before FORMAT_DESCRIPTION_EVENT: %#v\", ev)\n\t}\n\n\t// Strip the checksum, if any. We don't actually verify the checksum, so discard it.","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go#L515-L551","documentation":"A FORMAT_DESCRIPTION_EVENT was received but ev.Format() failed to decode it. Since the format description event defines how all subsequent events are parsed, vstreamer aborts parsing with the decode error and raw event data attached.","triggerScenarios":"ev.IsFormatDescription() is true but Format() returns an error — unsupported binlog version/format descriptor layout, truncated FDE payload, or corruption in the FDE.","commonSituations":"Streaming binlogs from a MySQL version/major release whose binlog format vitess doesn't support; corrupted FDE after crash; binlog encrypted with a scheme vitess can't read; restore from incompatible backup.","solutions":["Verify the source MySQL version is supported by this vitess release (check mysqlctl/flavor support) and the binlog format settings (binlog_format=ROW).","Check binlog file integrity on mysqld; if the FDE is corrupt, flush/purge logs (FLUSH LOGS / PURGE BINARY LOGS) and restart the stream from a valid GTID position.","If binlog encryption is enabled, either disable it or ensure vitess supports the encryption scheme for that MySQL flavor.","If the version should be supported, file a bug including the error text (it embeds the raw event data) and MySQL version."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// verify flavor/version support before streaming\nver := mysqlctl.ParseVersionString(serverVersion)\nif !supportedBinlogVersion(ver) {\n    return fmt.Errorf(\"MySQL %s binlog format not supported by this vitess release\", serverVersion)\n}","typeGuard":null,"tryCatchPattern":"err := vs.streamLog(ctx)\nif err != nil && strings.Contains(err.Error(), \"can't parse FORMAT_DESCRIPTION_EVENT\") {\n    // fall back: flush logs and restart from a fresh binlog file / known-good GTID\n    flushLogsAndRestartFromGTID(ctx)\n}","preventionTips":["Pin binlog_format=ROW and supported MySQL versions","Disable unsupported binlog encryption schemes","FLUSH/PURGE binary logs after crashes before resuming streams","Check upgrade notes when bumping MySQL major versions under vitess"],"tags":["vstreamer","binlog","format-description-event","mysql-version"],"backgroundTag":"binlog-event-parse-failure","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}