{"record":{"id":"d934d07a98d6fbc3","repo":"vitessio/vitess","slug":"controller-could-not-be-initialized-for-stream-v","errorCode":null,"errorMessage":"controller could not be initialized for stream %+v on tablet %v","messagePattern":"controller could not be initialized for stream %\\+v on tablet (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vdiff/engine.go","lineNumber":217,"sourceCode":"\t\t}\n\t\tif err := vde.openLocked(ctx); err == nil {\n\t\t\tlog.Info(\"VDiff engine: opened successfully\")\n\t\t\t// Don't invoke cancelRetry because openLocked\n\t\t\t// will hold on to this context for later cancellation.\n\t\t\tvde.cancelRetry = nil\n\t\t\tvde.mu.Unlock()\n\t\t\treturn\n\t\t}\n\t\tvde.mu.Unlock()\n\t}\n}\n\n// addController creates a new controller using the given vdiff record and adds it to the engine.\n// You must already have the main engine mutex (mu) locked before calling this.\nfunc (vde *Engine) addController(row sqltypes.RowNamedValues, options *tabletmanagerdata.VDiffOptions) error {\n\tct, err := newController(row, vde.dbClientFactoryDba, vde.ts, vde, options)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"controller could not be initialized for stream %+v on tablet %v\",\n\t\t\trow, vde.thisTablet.Alias)\n\t}\n\tvde.controllers[ct.id] = ct\n\tglobalStats.mu.Lock()\n\tdefer globalStats.mu.Unlock()\n\tglobalStats.controllers[ct.id] = ct\n\n\tcontrollerCtx, cancel := context.WithCancel(vde.ctx)\n\tct.cancel = cancel\n\tgo ct.run(controllerCtx)\n\treturn nil\n}\n\nfunc (vde *Engine) initControllers(qr *sqltypes.Result) error {\n\tif qr == nil || len(qr.Rows) == 0 {\n\t\treturn nil\n\t}\n\tfor _, row := range qr.Named().Rows {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vdiff/engine.go#L199-L235","documentation":"addController wraps a failure from newController (which builds a vdiff controller from a _vt.vdiff row) with this message. newController itself returns the underlying cause; this wrapper adds the stream row and tablet alias so operators know which vdiff and tablet failed during create/resume/retry.","triggerScenarios":"handleCreateResumeAction or initControllers/retryVDiffs calling addController where the vdiff row has invalid/missing fields (bad JSON in options, invalid position, malformed source/target), or required tablet/topology lookups inside newController fail.","commonSituations":"Corrupt _vt.vdiff row after a manual edit; keyspace/tablet missing from topo during resume after a topology change; a vdiff created against a source keyspace that no longer exists; incompatible options JSON written by an older version.","solutions":["Look at the wrapped inner error from newController in the same log chain — it names the real cause.","Validate the offending _vt.vdiff row (source, target, options columns) and delete/recreate the vdiff.","Verify topo connectivity and that the source/target tablets exist: vtctldclient GetTablets.","If resume keeps failing, delete the vdiff record and start a fresh VDiff Create."],"exampleFix":"// before (resume of corrupt row)\nvtctldclient vdiff --keyspace ks --workflow wf resume\n// -> controller could not be initialized ...\n// after\nvtctldclient vdiff --keyspace ks --workflow wf delete all\nvtctldclient vdiff --keyspace ks --workflow wf create","handlingStrategy":"try-catch","validationCode":"// before resume/create, check topo and row sanity\nerr := topoCheck(keyspace) // tablets exist\nrow, _ := db.Query(\"SELECT options FROM _vt.vdiff WHERE vdiff_uuid=?\", uuid)\njson.Valid(row[\"options\"]) // options column must be valid JSON","typeGuard":null,"tryCatchPattern":"err := vde.PerformVDiffAction(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"controller could not be initialized\") {\n  log.Error(err.Error()) // inspect wrapped cause\n  // fall back: delete all + recreate vdiff\n}","preventionTips":["Read the wrapped newController error for the root cause before retrying.","Keep topo healthy; verify tablets exist before resuming vdiffs.","Don't hand-edit _vt.vdiff rows; recreate the vdiff instead.","Avoid resuming vdiffs across version upgrades without recreating them."],"tags":["vdiff","controller","initialization","topology"],"backgroundTag":"vdiff-controller-init-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}