vitessio/vitess · error

got a real event before FORMAT_DESCRIPTION_EVENT: %#v

Error message

got a real event before FORMAT_DESCRIPTION_EVENT: %#v

What it means

vstreamer refuses to parse any binlog event that arrives before the FORMAT_DESCRIPTION_EVENT. Only a fake ROTATE_EVENT (sent by the primary to announce the current log file name) is legal before it, because the FORMAT_DESCRIPTION_EVENT establishes the event format (including checksum layout) needed to decode everything else. Any other event at that point means the stream is malformed or mis-sequenced.

Source

Thrown at go/vt/vttablet/tabletserver/vstreamer/vstreamer.go:548

		var err error
		vs.format, err = ev.Format()
		if err != nil {
			return nil, fmt.Errorf("can't parse FORMAT_DESCRIPTION_EVENT: %v, event data: %#v", err, ev)
		}
		vs.eventGTID = nil
		return nil, nil
	}

	// We can't parse anything until we get a FORMAT_DESCRIPTION_EVENT that
	// tells us the size of the event header.
	if vs.format.IsZero() {
		// The only thing that should come before the FORMAT_DESCRIPTION_EVENT
		// is a fake ROTATE_EVENT, which the primary sends to tell us the name
		// of the current log file.
		if ev.IsRotate() {
			return nil, nil
		}
		return nil, fmt.Errorf("got a real event before FORMAT_DESCRIPTION_EVENT: %#v", ev)
	}

	// Strip the checksum, if any. We don't actually verify the checksum, so discard it.
	ev, _, err := ev.StripChecksum(vs.format)
	if err != nil {
		return nil, fmt.Errorf("can't strip checksum from binlog event: %v, event data: %#v", err, ev)
	}

	shouldSend := func(evType binlogdatapb.VEventType) bool {
		if vs.eventTypesToStream != nil && !vs.eventTypesToStream[evType] {
			return false
		}
		return true
	}

	timeNowUnixNano := time.Now().UnixNano()
	var vevents []*binlogdatapb.VEvent
	switch {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the starting GTID/position points to a valid point in a binlog file where a FORMAT_DESCRIPTION_EVENT precedes your position
  2. Restart the VStream from the beginning of a binlog file or from a known-good GTID
  3. Check for proxies/binlog filters between Vitess and MySQL that may strip the FORMAT_DESCRIPTION_EVENT
  4. Confirm the primary's binlog files are intact (mysqlbinlog the file at that position)
Defensive patterns

Strategy: retry

Validate before calling

// Before streaming, sanity check the binlog file at the start position:
// mysqlbinlog --start-position=<pos> <logfile> | head
// The first event must be FORMAT_DESCRIPTION_EVENT (or a fake ROTATE).

Try / catch

err := streamErr
if strings.Contains(err.Error(), "got a real event before FORMAT_DESCRIPTION_EVENT") {
    // restart the vstream from the beginning of the binlog file / valid GTID
}

Prevention

When it happens

Trigger: parseEvent receives a real event (not a ROTATE_EVENT) while vs.format is still unset, i.e. before the server has sent the FORMAT_DESCRIPTION_EVENT on the binlog connection.

Common situations: Streaming from a server whose binlog stream starts mid-file without a format description; a replication bug or middleware/proxy that drops or reorders the initial events; resuming from a bad starting position on the binlog file.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/882ba59dfaf6ddfa. Report an issue: GitHub.