vitessio/vitess · error

both atomic copy and partial mode cannot be specified for th

Error message

both atomic copy and partial mode cannot be specified for the same workflow

What it means

The materializer refuses to create a vreplication workflow that requests both atomic copy and partial mode simultaneously, because these are mutually exclusive copy strategies. getWorkflowSubType maps the materializer's flags (isPartial and ms.AtomicCopy) to a VReplicationWorkflowSubType, and the combination is considered invalid input. It returns VReplicationWorkflowSubType_None along with this error so callers like createWorkflowStreams abort stream creation.

Source

Thrown at go/vt/vtctl/workflow/materializer.go:100

func (mz *materializer) getWorkflowType() binlogdatapb.VReplicationWorkflowType {
	var workflowType binlogdatapb.VReplicationWorkflowType
	switch mz.ms.MaterializationIntent {
	case vtctldatapb.MaterializationIntent_CUSTOM:
		workflowType = binlogdatapb.VReplicationWorkflowType_Materialize
	case vtctldatapb.MaterializationIntent_MOVETABLES:
		workflowType = binlogdatapb.VReplicationWorkflowType_MoveTables
	case vtctldatapb.MaterializationIntent_CREATELOOKUPINDEX:
		workflowType = binlogdatapb.VReplicationWorkflowType_CreateLookupIndex
	}
	return workflowType
}

func (mz *materializer) getWorkflowSubType() (binlogdatapb.VReplicationWorkflowSubType, error) {
	switch {
	case mz.isPartial && mz.ms.AtomicCopy:
		return binlogdatapb.VReplicationWorkflowSubType_None,
			errors.New("both atomic copy and partial mode cannot be specified for the same workflow")
	case mz.isPartial:
		return binlogdatapb.VReplicationWorkflowSubType_Partial, nil
	case mz.ms.AtomicCopy:
		return binlogdatapb.VReplicationWorkflowSubType_AtomicCopy, nil
	default:
		return binlogdatapb.VReplicationWorkflowSubType_None, nil
	}
}

func (mz *materializer) getOptionsJSON() (string, error) {
	defaultJSON := "{}"
	if mz.ms.WorkflowOptions == nil {
		return defaultJSON, nil
	}
	optionsJSON, err := json.Marshal(mz.ms.WorkflowOptions)
	if err != nil || optionsJSON == nil {
		return defaultJSON, err
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Remove the AtomicCopy flag from the workflow invocation since partial mode is already in effect, or vice versa.
  2. If an atomic copy is required, recreate/extend the workflow so it copies all tables in one shot instead of partial mode.
  3. Check the workflow spec/CLI flags for conflicting options before launching; only set one of AtomicCopy or partial.

Example fix

// before
mz := newMaterializer(ts, ctx, spec) // spec.AtomicCopy=true, workflow is partial
subType, err := mz.getWorkflowSubType() // error
// after
spec.AtomicCopy = false // drop atomic copy for partial workflows
subType, err := mz.getWorkflowSubType() // VReplicationWorkflowSubType_Partial
Defensive patterns

Strategy: validation

Validate before calling

if mz.isPartial && mz.ms.AtomicCopy {
    return fmt.Errorf("cannot specify both atomic copy and partial mode for workflow %s", mz.ms.Workflow)
}

Try / catch

if err := launchWorkflow(spec); err != nil {
    if strings.Contains(err.Error(), "both atomic copy and partial mode") {
        spec.AtomicCopy = false
        return launchWorkflow(spec)
    }
    return err
}

Prevention

When it happens

Trigger: Calling MoveTables/LaunchMaterialize (createWorkflowStreams or generateInserts path) with a MaterializerSpec whose AtomicCopy flag is true while the workflow was detected as partial (isPartial, e.g. only a subset of tables/columns being copied in an existing workflow).

Common situations: A user passes --atomic-copy (or sets AtomicCopy in the spec) on a MoveTables command that is only copying a partial set of tables into an existing workflow, or two tooling layers each set one of the flags independently.

Related errors


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