vitessio/vitess · warning

ErrNoSemiSync

ErrNoSemiSync

Error message

semi-sync plugin not loaded

What it means

ErrNoSemiSync is a sentinel error (errors.Is-comparable) indicating the semi-sync replication plugin (rpl_semi_sync_master/replica) is not loaded in mysqld. enableSemiSyncQuery and semiSyncReplicationStatusQuery return it when the semi-sync status variable doesn't exist because the plugin was never installed. Callers can use errors.Is to branch on it gracefully rather than treating it as a hard failure.

Source

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

	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:
		return "SET GLOBAL rpl_semi_sync_master_enabled = %v, GLOBAL rpl_semi_sync_slave_enabled = %v", nil
	}
	return "", ErrNoSemiSync
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Load the plugin: INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so' (and the master/source equivalent) on the mysqld instance.
  2. Check SemiSyncExtensionLoaded / SemiSyncType first and skip semi-sync setup when the plugin is absent.
  3. On MySQL 8.0.26+, account for the source/replica variable renaming — use the correct variable names for the server version.
  4. Compare with errors.Is(err, mysqlctl.ErrNoSemiSync) to treat absence as an expected, non-fatal condition.

Example fix

// before
_, err := mysqld.SemiSyncReplicationStatus(ctx)
if err != nil {
    return err
}

// after
_, err := mysqld.SemiSyncReplicationStatus(ctx)
if errors.Is(err, mysqlctl.ErrNoSemiSync) {
    log.Info("semi-sync plugin not loaded; continuing without semi-sync")
    return nil
} else if err != nil {
    return vterrors.Wrapf(err, "checking semi-sync status")
}
Defensive patterns

Strategy: type-guard

Validate before calling

loaded, semiSyncType := mysqld.SemiSyncExtensionLoaded(ctx)
if !loaded {
    log.Info("semi-sync extension not loaded; skipping semi-sync setup")
}

Type guard

func isSemiSyncMissing(err error) bool {
    return errors.Is(err, mysqlctl.ErrNoSemiSync)
}

Try / catch

status, err := mysqld.SemiSyncReplicationStatus(ctx)
switch {
case errors.Is(err, mysqlctl.ErrNoSemiSync):
    // expected: plugin absent, degrade gracefully
case err != nil:
    return vterrors.Wrapf(err, "semi-sync status")
default:
    _ = status
}

Prevention

When it happens

Trigger: Calling SemiSyncReplicationStatus (or code paths via enableSemiSyncQuery / semiSyncReplicationStatusQuery) on a mysqld without the semi-sync plugin loaded: the SHOW query for the semi-sync status variable returns no rows / unknown variable, and the function returns ErrNoSemiSync.

Common situations: MySQL 8.0.26+ renamed plugin variables (rpl_semi_sync_master_* -> rpl_semi_sync_source_*), leaving the plugin effectively unloaded under the old names; semi-sync plugin never installed via INSTALL PLUGIN; vanilla MySQL community builds without semi-sync compiled in.

Related errors


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