vitessio/vitess · error

cannot switch traffic for workflow %s at this time: %s

Error message

cannot switch traffic for workflow %s at this time: %s

What it means

SwitchTraffic first runs canSwitch(keyspace, workflowName), which returns a human-readable reason string when conditions for switching read/write traffic are not yet met (e.g. vreplication streams not caught up, wrong workflow state). A non-empty reason aborts the switch with this wrapped error.

Source

Thrown at go/vt/wrangler/workflow.go:344

	if vrw.workflowType == MigrateWorkflow {
		return nil, errors.New("invalid action for Migrate workflow: SwitchTraffic")
	}

	vrw.params.Direction = direction

	workflowName := vrw.params.Workflow
	keyspace := vrw.params.TargetKeyspace
	if vrw.params.Direction == workflow.DirectionBackward {
		workflowName = workflow.ReverseWorkflowName(workflowName)
		keyspace = vrw.params.SourceKeyspace
	}

	reason, err := vrw.canSwitch(keyspace, workflowName)
	if err != nil {
		return nil, err
	}
	if reason != "" {
		return nil, fmt.Errorf("cannot switch traffic for workflow %s at this time: %s", workflowName, reason)
	}

	hasReplica, hasRdonly, hasPrimary, err = vrw.parseTabletTypes()
	if err != nil {
		return nil, err
	}
	if hasReplica || hasRdonly {
		if rdDryRunResults, err = vrw.switchReads(); err != nil {
			return nil, err
		}
	}
	if rdDryRunResults != nil {
		dryRunResults = append(dryRunResults, *rdDryRunResults...)
	}
	if hasPrimary {
		if wrDryRunResults, err = vrw.switchWrites(); err != nil {
			return nil, err
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Read the reason embedded in the error and address it (most often: wait for target catch-up, check VReplicationWorkflow streams)
  2. Verify workflow state with the appropriate status commands; resume/restart stuck streams
  3. Retry the switch once the reason condition clears
Defensive patterns

Strategy: retry

Validate before calling

reason, err := canSwitch(keyspace, workflowName)
if err != nil || reason != "" {
    // not ready: wait / fix prerequisite, then retry
}

Try / catch

err := retry.Do(func() error {
    _, err := wf.SwitchTraffic(ctx, ...)
    if err != nil && strings.Contains(err.Error(), "cannot switch traffic") {
        return retry.TransientError(err) // retry after catch-up
    }
    return err
}, retry.Attempts(timeout/retryInterval))

Prevention

When it happens

Trigger: Calling SwitchTraffic (or ReverseTraffic, or testSwitchForward) when canSwitch returns a non-empty reason — commonly replication lag on the target, streams not running, or the workflow not in the expected state.

Common situations: Running PlannedSwitchOver before the target has fully caught up; reverse traffic attempted too soon after a forward switch; a stuck/failed vreplication stream leaving the workflow in a non-switchable state.

Related errors


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