vitessio/vitess · error

GetPreviousGTIDs: previous GTIDs not found

Error message

GetPreviousGTIDs: previous GTIDs not found

What it means

GetPreviousGTIDs scans binlog events (SHOW BINLOG EVENTS) looking for the Previous_gtids event that records the set of GTIDs executed before the current binlog file. If no such event exists in the scanned binlog, this error is returned. This usually means the binlog file is empty, freshly rotated, or the server has GTIDs disabled.

Source

Thrown at go/vt/mysqlctl/replication.go:1217

	return binaryLogs, err
}

// GetPreviousGTIDs is part of the MysqlDaemon interface.
func (mysqld *Mysqld) GetPreviousGTIDs(ctx context.Context, binlog string) (previousGtids string, err error) {
	query := fmt.Sprintf("SHOW BINLOG EVENTS IN '%s' LIMIT 2", binlog)
	qr, err := mysqld.FetchSuperQuery(ctx, query)
	if err != nil {
		return previousGtids, err
	}
	previousGtidsFound := false
	for _, row := range qr.Named().Rows {
		if row.AsString("Event_type", "") == "Previous_gtids" {
			previousGtids = row.AsString("Info", "")
			previousGtidsFound = true
		}
	}
	if !previousGtidsFound {
		return previousGtids, errors.New("GetPreviousGTIDs: previous GTIDs not found")
	}
	return previousGtids, nil
}

var ErrNoSemiSync = errors.New("semi-sync plugin not loaded")

func (mysqld *Mysqld) SemiSyncType(ctx context.Context) mysql.SemiSyncType {
	if mysqld.semiSyncType == mysql.SemiSyncTypeUnknown {
		mysqld.semiSyncType, _ = mysqld.SemiSyncExtensionLoaded(ctx)
	}
	return mysqld.semiSyncType
}

func (mysqld *Mysqld) enableSemiSyncQuery(ctx context.Context) (string, error) {
	switch mysqld.SemiSyncType(ctx) {
	case mysql.SemiSyncTypeSource:
		return "SET GLOBAL rpl_semi_sync_source_enabled = %v, GLOBAL rpl_semi_sync_replica_enabled = %v", nil
	case mysql.SemiSyncTypeMaster:

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify gtid_mode=ON on the server; Previous_gtids events only exist when GTIDs are enabled.
  2. Query the first binlog file in the series (SHOW BINARY LOGS) rather than a file that may be empty/rotated.
  3. Fall back to reading executed GTIDs from @@GLOBAL.gtid_executed if the binlog event is unavailable.
  4. If the binlog was purged, restore from a backup that still has the needed binlogs.
Defensive patterns

Strategy: fallback

Validate before calling

gtidMode, err := mysqld.FetchSuperQuery(ctx, "SELECT @@GLOBAL.gtid_mode")
// proceed only if gtidMode == "ON" and the target binlog file has events

Try / catch

gtids, err := mysqld.GetPreviousGTIDs(ctx, binlogFile)
if err != nil {
    if strings.Contains(err.Error(), "previous GTIDs not found") {
        gtids, err = readFromGtidExecuted(ctx, mysqld) // fallback to @@GLOBAL.gtid_executed
    }
    if err != nil {
        return vterrors.Wrapf(err, "resolving previous GTIDs")
    }
}

Prevention

When it happens

Trigger: Calling Mysqld.GetPreviousGTIDs when SHOW BINLOG EVENTS on the target binlog file contains no row with Event_type == 'Previous_gtids' (previousGtidsFound stays false), producing "GetPreviousGTIDs: previous GTIDs not found".

Common situations: Point-in-time recovery / GTID position calculation against a brand-new binlog file with no prior events; GTID mode disabled (gtid_mode=OFF) so Previous_gtids events never exist; purged or truncated binlogs on the server.

Related errors


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