vitessio/vitess · error

failed to ensure replication was started on tablet %s after

Error message

failed to ensure replication was started on tablet %s after RestartReplication error (%v): %w

What it means

restartReplication issues RestartReplication on a tablet and, if that call fails, attempts a compensating StartReplication to ensure replication is at least running. If StartReplication also fails, the two errors are combined into this wrapped error: the outer message names the tablet and the StartReplication failure, and %w preserves the original RestartReplication error so callers can still match on it.

Source

Thrown at go/vt/vtorc/logic/topology_recovery.go:666

	// when the RPC never reached the tablet, in which case STOP cannot have run.
	if ctx.Err() != nil || status.Code(err) == codes.Unavailable {
		return err
	}

	// TODO: Remove this StartReplication fallback in v26, when all supported
	// vttablets include detached post-STOP cleanup in RestartReplication.
	tabletAlias := topoproto.TabletAliasString(tablet.Alias)
	logger.Warn("RestartReplication failed; attempting to ensure replication is started",
		slog.String("tablet", tabletAlias),
		slog.Any("error", err),
	)

	startCtx, startCancel := context.WithTimeout(context.WithoutCancel(ctx), topo.RemoteOperationTimeout)
	defer startCancel()
	if startErr := tmc.StartReplication(startCtx, tablet, semiSync); startErr != nil {
		// Wrap with %w (not vterrors.Wrapf, which has no Unwrap) so callers can
		// still match on the original RestartReplication error.
		return fmt.Errorf("failed to ensure replication was started on tablet %s after RestartReplication error (%v): %w", tabletAlias, startErr, err)
	}

	return err
}

// isERSEnabled returns true if ERS can be used globally or for the given keyspace.
func isERSEnabled(analysisEntry *inst.DetectionAnalysis) bool {
	// If ERS is disabled globally we have no way of repairing the cluster.
	if !config.ERSEnabled() {
		log.Info(fmt.Sprintf("VTOrc not configured to run ERS, skipping recovering %v", analysisEntry.Analysis))
		return false
	}

	// Return false if ERS is disabled on the keyspace.
	if analysisEntry.AnalyzedKeyspaceEmergencyReparentDisabled {
		log.Info(fmt.Sprintf("ERS is disabled on keyspace %s, skipping recovering %v", analysisEntry.AnalyzedKeyspace, analysisEntry.Analysis))
		return false
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Read the wrapped (%w) original RestartReplication error plus the startErr to see the root cause
  2. Confirm the replica tablet and its mysqld are actually up (vtctldclient GetTablet / check the tablet's logs)
  3. Manually run START REPLICA on the replica's MySQL to restore replication, then re-run recovery
  4. Check semi-sync configuration — after primary loss, replicas may block; adjust rpl_semi_sync settings or disable semi-sync temporarily

Example fix

// root cause visible in the wrapped error
if err != nil {
    var orig *mysql.SQLError
    if errors.As(err, &orig) { /* handle original RestartReplication error */ }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe tablet reachability before restart
err := tmc.Ping(ctx, tablet)

Try / catch

err := restartReplication(ctx, tablet, semiSync)
if err != nil {
    orig := err
    if unwrapped := errors.Unwrap(err); unwrapped != nil { orig = unwrapped }
    log.Error("replication restart failed", slog.Any("error", orig))
}

Prevention

When it happens

Trigger: A replication restart during recovery fails (err != nil), the fallback tmc.StartReplication startErr is also non-nil — typically both fail because the tablet is unreachable, the tablet's MySQL is down, or semi-sync settings conflict.

Common situations: Recovering after a primary failure where replicas are also down or partitioned; mysqld not running on the replica; tabletmanager RPC auth/TLS misconfiguration; semi-sync replica count impossible after primary loss.

Related errors


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