vitessio/vitess · error

can't get GTID from binlog event: %v, event data: %#v

Error message

can't get GTID from binlog event: %v, event data: %#v

What it means

For pseudo (e.g. PREVIOUS_GTIDS/anonymous) events, parseEvents extracts the GTID via ev.GTID(format) to track stream position. If GTID extraction fails — the event's GTID format is unsupported or the buffer is malformed — the streamer cannot maintain position and aborts.

Source

Thrown at go/vt/binlog/binlog_streamer.go:350

			// is a fake ROTATE_EVENT, which the primary sends to tell us the name
			// of the current log file.
			if ev.IsRotate() {
				continue
			}
			return pos, 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(format)
		if err != nil {
			return pos, fmt.Errorf("can't strip checksum from binlog event: %v, event data: %#v", err, ev)
		}

		switch {
		case ev.IsPseudo():
			gtid, _, _, _, err = ev.GTID(format)
			if err != nil {
				return pos, fmt.Errorf("can't get GTID from binlog event: %v, event data: %#v", err, ev)
			}
			oldpos := pos
			pos = replication.AppendGTID(pos, gtid)
			// If the event is received outside of a transaction, it must
			// be sent. Otherwise, it will get lost and the targets will go out
			// of sync.
			if autocommit && !pos.Equal(oldpos) {
				if err = commit(ev.Timestamp()); err != nil {
					return pos, err
				}
			}
		case ev.IsGTID(): // GTID_EVENT: update current GTID, maybe BEGIN.
			var hasBegin bool
			gtid, hasBegin, _, _, err = ev.GTID(format)
			if err != nil {
				return pos, fmt.Errorf("can't get GTID from binlog event: %v, event data: %#v", err, ev)
			}
			pos = replication.AppendGTID(pos, gtid)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Ensure the source server's GTID mode/flavor matches what Vitess expects (gtid_mode=ON for MySQL; matching MariaDB flavor builds)
  2. Check that the tablet is built with support for the source's GTID flavor
  3. Validate the binlog with mysqlbinlog to rule out corruption
  4. Restart the stream from a known-good position; if it persists, upgrade Vitess
  5. If GTID is intentionally off, confirm the flavor's GTID representation is still parseable by Vitess
Defensive patterns

Strategy: validation

Validate before calling

// confirm GTID mode is configured consistently before streaming
// mysql> SELECT @@global.gtid_mode; -- expect ON for MySQL sources

Try / catch

if err := streamer.Stream(ctx); err != nil {
	if strings.Contains(err.Error(), "can't get GTID") {
		// GTID flavor mismatch/corruption: verify gtid_mode and flavor, restart from good position
	}
}

Prevention

When it happens

Trigger: During Stream/parseEvents, ev.IsPseudo() is true and ev.GTID(format) errors — e.g. a GTID flavor (MySQL, MariaDB) the client cannot decode, or corrupt GTID payload bytes.

Common situations: Mixing GTID modes/flavors (MySQL GTID vs MariaDB) across a topology; binlog data from an unsupported server version; corrupted GTID event payload.

Related errors


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