vitessio/vitess · error

workflow has already been created, state is %s

Error message

workflow has already been created, state is %s

What it means

VReplicationWorkflow.Create guards against double-creation: after the Exists() check, it also checks the cached workflow state. If the state is anything other than WorkflowStateNotCreated, the workflow object has already been initialized/created in this session and Create is called again, which is invalid.

Source

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

					stateInfo = append(stateInfo, "All Reads Switched")
					stateInfo = append(stateInfo, "All Writes Switched")
				}
			}
		} else {
			stateInfo = append(stateInfo, "Writes Not Switched")
		}
	}
	return strings.Join(stateInfo, ". ")
}

// Create initiates a workflow
func (vrw *VReplicationWorkflow) Create(ctx context.Context) error {
	var err error
	if vrw.Exists() {
		return errors.New("workflow already exists")
	}
	if vrw.CachedState() != WorkflowStateNotCreated {
		return fmt.Errorf("workflow has already been created, state is %s", vrw.CachedState())
	}
	switch vrw.workflowType {
	case MoveTablesWorkflow, MigrateWorkflow:
		err = vrw.initMoveTables()
	case ReshardWorkflow:
		excludeTables := strings.Split(vrw.params.ExcludeTables, ",")
		keyspace := vrw.params.SourceKeyspace

		vschmErr := vrw.wr.ValidateVSchema(ctx, keyspace, vrw.params.SourceShards, excludeTables, true /*includeViews*/)
		if vschmErr != nil {
			return fmt.Errorf("Create ReshardWorkflow failed: %v", vschmErr)
		}

		err = vrw.initReshard()
	default:
		return fmt.Errorf("unknown workflow type %d", vrw.workflowType)
	}
	if err != nil {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Only call Create once per workflow object, after confirming CachedState() == WorkflowStateNotCreated
  2. If the workflow already exists remotely, skip Create and resume with the appropriate later phase (e.g. SwitchTraffic)
  3. Recreate the VReplicationWorkflow object fresh from params before calling Create again

Example fix

// before
wf.Create(ctx) // may run twice
// after
if wf.CachedState() == WorkflowStateNotCreated && !wf.Exists() {
    wf.Create(ctx)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if wf.Exists() || wf.CachedState() != WorkflowStateNotCreated {
    return nil // already created; skip Create
}

Type guard

func canCreate(w *wrangler.VReplicationWorkflow) bool {
    return !w.Exists() && w.CachedState() == wrangler.WorkflowStateNotCreated
}

Try / catch

if err := wf.Create(ctx); err != nil {
    if strings.Contains(err.Error(), "already") {
        return nil // idempotent: treat as success
    }
    return err
}

Prevention

When it happens

Trigger: Calling VReplicationWorkflow.Create(ctx) on a workflow whose CachedState() is not WorkflowStateNotCreated — i.e. Create (or an equivalent init) was already invoked on this object.

Common situations: Retrying a failed orchestration script that re-uses the same workflow object; calling Create after another method already transitioned the state; double-invocation from concurrent tooling paths.

Related errors


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