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
- Only call Create once per workflow object, after confirming CachedState() == WorkflowStateNotCreated
- If the workflow already exists remotely, skip Create and resume with the appropriate later phase (e.g. SwitchTraffic)
- 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
- Call Create exactly once per workflow object
- Guard orchestration retries with Exists()/CachedState() checks
- Make orchestration code idempotent around workflow creation
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
- value out of range
- both atomic copy and partial mode cannot be specified for th
- invalid workflow
- multiple source keyspaces for a single workflow
- multiple target keyspaces for a single workflow
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/ee635a74d100a32b.
Report an issue: GitHub.