vitessio/vitess · error · ErrMultipleTargetKeyspaces

multiple target keyspaces for a single workflow

Error message

multiple target keyspaces for a single workflow

What it means

ErrMultipleTargetKeyspaces is returned by scanWorkflow when a single workflow's streams report multiple target keyspaces across shard primaries. Healthy workflows always replicate into exactly one target keyspace, so this sentinel flags inconsistent workflow metadata.

Source

Thrown at go/vt/vtctl/workflow/server.go:126

	lockTablesCycles = 2
	// Time to wait between LOCK TABLES cycles on the sources during SwitchWrites.
	lockTablesCycleDelay = time.Duration(100 * time.Millisecond)

	SqlUnfreezeWorkflow = "update _vt.vreplication set state='Running', message='' where db_name=%a and workflow=%a"
)

var (
	// ErrInvalidWorkflow is a catchall error type for conditions that should be
	// impossible when operating on a workflow.
	ErrInvalidWorkflow = errors.New("invalid workflow")
	// ErrMultipleSourceKeyspaces occurs when a workflow somehow has multiple
	// source keyspaces across different shard primaries. This should be
	// impossible.
	ErrMultipleSourceKeyspaces = errors.New("multiple source keyspaces for a single workflow")
	// ErrMultipleTargetKeyspaces occurs when a workflow somehow has multiple
	// target keyspaces across different shard primaries. This should be
	// impossible.
	ErrMultipleTargetKeyspaces          = errors.New("multiple target keyspaces for a single workflow")
	ErrWorkflowCompleteNotFullySwitched = errors.New("cannot complete workflow because you have not yet switched all read and write traffic")
	ErrWorkflowDeleteWritesSwitched     = errors.New("cannot delete workflow because you have already switched write traffic")
)

// Server provides an API to work with Vitess workflows, like vreplication
// workflows (MoveTables, Reshard, etc) and schema migration workflows.
type Server struct {
	ts  *topo.Server
	tmc tmclient.TabletManagerClient
	// Limit the number of concurrent background goroutines if needed.
	sem     *semaphore.Weighted
	env     *vtenv.Environment
	options serverOptions
}

// NewServer returns a new server instance with the given topo.Server and
// TabletManagerClient.
func NewServer(env *vtenv.Environment, ts *topo.Server, tmc tmclient.TabletManagerClient, opts ...ServerOption) *Server {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Query _vt.vreplication on the target shards and identify streams whose target keyspace differs.
  2. Delete the stale/inconsistent streams so only one target keyspace remains.
  3. Recreate the workflow cleanly if reconciliation is not feasible.

Example fix

// before
streams targeting keyspaces: customer and customer_new under workflow 'sales' -> error
// after
delete from _vt.vreplication where workflow='sales' and db_name='customer_new';
// workflow now has a single target keyspace
Defensive patterns

Strategy: type-guard

Validate before calling

targets := distinctTargetKeyspaces(keyspace, workflow)
if len(targets) > 1 { return workflow.ErrMultipleTargetKeyspaces }

Type guard

func isMultipleTargetKeyspaces(err error) bool {
    return errors.Is(err, workflow.ErrMultipleTargetKeyspaces)
}

Try / catch

if err := op(ctx, ks, wf); err != nil {
    if errors.Is(err, workflow.ErrMultipleTargetKeyspaces) {
        // clean up stale streams in the extra target keyspace
    }
    return err
}

Prevention

When it happens

Trigger: scanWorkflow encountering _vt.vreplication rows whose specs point at different target keyspaces for the same workflow name.

Common situations: Leftover streams from a partially cleaned-up workflow, manual metadata edits, or a workflow name collision across operations that wrote rows into both keyspaces.

Related errors


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