{"record":{"id":"bd233bb87a272a87","repo":"vitessio/vitess","slug":"cannot-switch-traffic-for-workflow-s-at-this-time","errorCode":null,"errorMessage":"cannot switch traffic for workflow %s at this time: %s","messagePattern":"cannot switch traffic for workflow (.+?) at this time: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/wrangler/workflow.go","lineNumber":344,"sourceCode":"\tif vrw.workflowType == MigrateWorkflow {\n\t\treturn nil, errors.New(\"invalid action for Migrate workflow: SwitchTraffic\")\n\t}\n\n\tvrw.params.Direction = direction\n\n\tworkflowName := vrw.params.Workflow\n\tkeyspace := vrw.params.TargetKeyspace\n\tif vrw.params.Direction == workflow.DirectionBackward {\n\t\tworkflowName = workflow.ReverseWorkflowName(workflowName)\n\t\tkeyspace = vrw.params.SourceKeyspace\n\t}\n\n\treason, err := vrw.canSwitch(keyspace, workflowName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif reason != \"\" {\n\t\treturn nil, fmt.Errorf(\"cannot switch traffic for workflow %s at this time: %s\", workflowName, reason)\n\t}\n\n\thasReplica, hasRdonly, hasPrimary, err = vrw.parseTabletTypes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif hasReplica || hasRdonly {\n\t\tif rdDryRunResults, err = vrw.switchReads(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif rdDryRunResults != nil {\n\t\tdryRunResults = append(dryRunResults, *rdDryRunResults...)\n\t}\n\tif hasPrimary {\n\t\tif wrDryRunResults, err = vrw.switchWrites(); err != nil {\n\t\t\treturn nil, err\n\t\t}","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/wrangler/workflow.go#L326-L362","documentation":"SwitchTraffic first runs canSwitch(keyspace, workflowName), which returns a human-readable reason string when conditions for switching read/write traffic are not yet met (e.g. vreplication streams not caught up, wrong workflow state). A non-empty reason aborts the switch with this wrapped error.","triggerScenarios":"Calling SwitchTraffic (or ReverseTraffic, or testSwitchForward) when canSwitch returns a non-empty reason — commonly replication lag on the target, streams not running, or the workflow not in the expected state.","commonSituations":"Running PlannedSwitchOver before the target has fully caught up; reverse traffic attempted too soon after a forward switch; a stuck/failed vreplication stream leaving the workflow in a non-switchable state.","solutions":["Read the reason embedded in the error and address it (most often: wait for target catch-up, check VReplicationWorkflow streams)","Verify workflow state with the appropriate status commands; resume/restart stuck streams","Retry the switch once the reason condition clears"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"reason, err := canSwitch(keyspace, workflowName)\nif err != nil || reason != \"\" {\n    // not ready: wait / fix prerequisite, then retry\n}","typeGuard":null,"tryCatchPattern":"err := retry.Do(func() error {\n    _, err := wf.SwitchTraffic(ctx, ...)\n    if err != nil && strings.Contains(err.Error(), \"cannot switch traffic\") {\n        return retry.TransientError(err) // retry after catch-up\n    }\n    return err\n}, retry.Attempts(timeout/retryInterval))","preventionTips":["Wait for target replication catch-up before switching traffic","Check workflow state/status before attempting switch or reverse traffic","Never run ReverseTraffic immediately after ForwardTraffic without confirming state"],"tags":["vreplication","switch-traffic","workflow","prerequisites"],"backgroundTag":"workflow-prerequisites-not-met","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}