vitessio/vitess · error

either source or target shards are missing

Error message

either source or target shards are missing

What it means

Validation of a VReplication workflow (e.g. MoveTables completion validation) requires both source and target shard lists to be non-empty so their sharding key ranges can be parsed. If either list is empty, getSourceAndTargetKeyRanges rejects the call before any shard comparison is possible.

Solutions

  1. Verify the workflow was created correctly with explicit source/target shards (MoveTables --source or same-keyspace shard specs)
  2. Check the keyspace actually has shards in topology (vtctldclient GetTablets / GetShards) before validating completion
  3. Fix the caller so it only invokes isPartialMoveTables after ShardSet is populated

Example fix

// before: empty shard list
sourceShards := []string{}
kr, _, err := getSourceAndTargetKeyRanges(sourceShards, targetShards)
// after: guard at the caller
if len(sourceShards) == 0 || len(targetShards) == 0 {
    return fmt.Errorf("workflow has no source/target shards loaded")
}
kr, _, err := getSourceAndTargetKeyRanges(sourceShards, targetShards)
Defensive patterns

Strategy: validation

Validate before calling

if len(workflow.SourceShards) == 0 || len(workflow.TargetShards) == 0 {
    return errors.New("workflow must have non-empty source and target shard sets before validation")
}

Prevention

When it happens

Trigger: Calling isPartialMoveTables / workflow validation with an empty sourceShards or targetShards slice — typically the ShardSet was never populated on the workflow, or a caller passed empty shard specs.

Common situations: Programmatic use of the workflow API with shards not yet loaded from topology, a MoveTables workflow created against a keyspace with zero shards, or a typo/mis-configuration leaving the shard list unset.

Related errors


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

Appendix: source

Thrown at go/vt/vtctl/workflow/utils.go:443

	if len(targets) == 0 {
		return nil, fmt.Errorf("%w in keyspace %s for %s", ErrNoStreams, targetKeyspace, workflow)
	}

	return &TargetInfo{
		Targets:         targets,
		Frozen:          frozen,
		OptCells:        optCells,
		OptTabletTypes:  optTabletTypes,
		WorkflowType:    workflowType,
		WorkflowSubType: workflowSubType,
		Options:         &options,
	}, nil
}

func getSourceAndTargetKeyRanges(sourceShards, targetShards []string) (*topodatapb.KeyRange, *topodatapb.KeyRange, error) {
	if len(sourceShards) == 0 || len(targetShards) == 0 {
		return nil, nil, errors.New("either source or target shards are missing")
	}

	getKeyRange := func(shard string) (*topodatapb.KeyRange, error) {
		krs, err := key.ParseShardingSpec(shard)
		if err != nil {
			return nil, err
		}
		return krs[0], nil
	}

	// Happily string sorting of shards also sorts them in the ascending order of key
	// ranges in vitess.
	sort.Strings(sourceShards)
	sort.Strings(targetShards)
	getFullKeyRange := func(shards []string) (*topodatapb.KeyRange, error) {
		// Expect sorted shards.
		kr1, err := getKeyRange(shards[0])
		if err != nil {

View on GitHub (pinned to 01a25a7d17)