{"record":{"id":"ee635a74d100a32b","repo":"vitessio/vitess","slug":"workflow-has-already-been-created-state-is-s","errorCode":null,"errorMessage":"workflow has already been created, state is %s","messagePattern":"workflow has already been created, state is (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/wrangler/workflow.go","lineNumber":239,"sourceCode":"\t\t\t\t\tstateInfo = append(stateInfo, \"All Reads Switched\")\n\t\t\t\t\tstateInfo = append(stateInfo, \"All Writes Switched\")\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tstateInfo = append(stateInfo, \"Writes Not Switched\")\n\t\t}\n\t}\n\treturn strings.Join(stateInfo, \". \")\n}\n\n// Create initiates a workflow\nfunc (vrw *VReplicationWorkflow) Create(ctx context.Context) error {\n\tvar err error\n\tif vrw.Exists() {\n\t\treturn errors.New(\"workflow already exists\")\n\t}\n\tif vrw.CachedState() != WorkflowStateNotCreated {\n\t\treturn fmt.Errorf(\"workflow has already been created, state is %s\", vrw.CachedState())\n\t}\n\tswitch vrw.workflowType {\n\tcase MoveTablesWorkflow, MigrateWorkflow:\n\t\terr = vrw.initMoveTables()\n\tcase ReshardWorkflow:\n\t\texcludeTables := strings.Split(vrw.params.ExcludeTables, \",\")\n\t\tkeyspace := vrw.params.SourceKeyspace\n\n\t\tvschmErr := vrw.wr.ValidateVSchema(ctx, keyspace, vrw.params.SourceShards, excludeTables, true /*includeViews*/)\n\t\tif vschmErr != nil {\n\t\t\treturn fmt.Errorf(\"Create ReshardWorkflow failed: %v\", vschmErr)\n\t\t}\n\n\t\terr = vrw.initReshard()\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown workflow type %d\", vrw.workflowType)\n\t}\n\tif err != nil {","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/wrangler/workflow.go#L221-L257","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nwf.Create(ctx) // may run twice\n// after\nif wf.CachedState() == WorkflowStateNotCreated && !wf.Exists() {\n    wf.Create(ctx)\n}","handlingStrategy":"type-guard","validationCode":"if wf.Exists() || wf.CachedState() != WorkflowStateNotCreated {\n    return nil // already created; skip Create\n}","typeGuard":"func canCreate(w *wrangler.VReplicationWorkflow) bool {\n    return !w.Exists() && w.CachedState() == wrangler.WorkflowStateNotCreated\n}","tryCatchPattern":"if err := wf.Create(ctx); err != nil {\n    if strings.Contains(err.Error(), \"already\") {\n        return nil // idempotent: treat as success\n    }\n    return err\n}","preventionTips":["Call Create exactly once per workflow object","Guard orchestration retries with Exists()/CachedState() checks","Make orchestration code idempotent around workflow creation"],"tags":["vreplication","workflow","state","double-create"],"backgroundTag":"workflow-already-created","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}