{"record":{"id":"c9025783314da456","repo":"vitessio/vitess","slug":"expecting-field-event-first-got-v-c90257","errorCode":null,"errorMessage":"expecting field event first, got: %v","messagePattern":"expecting field event first, got: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/vcopier_atomic.go","lineNumber":164,"sourceCode":"\t\t\t\tcopyWorkQueue.close()\n\t\t\t}\n\t\t\tcopyWorkQueue = vc.newCopyWorkQueue(parallelism, copyWorkerFactory)\n\t\t\tif state.currentTableName != \"\" {\n\t\t\t\tlog.Info(fmt.Sprintf(\"copy of table %s is done at lastpk %+v\", state.currentTableName, lastpkbv))\n\t\t\t\tif err := vc.runPostCopyActionsAndDeleteCopyState(ctx, stopCtx, state.currentTableName); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlog.Info(\"starting copy phase with table \" + tableName)\n\t\t\t}\n\n\t\t\tstate.currentTableName = tableName\n\t\t}\n\n\t\t// A new copy queue is created for each table. The queue is closed when the table is done.\n\t\tif !copyWorkQueue.isOpen {\n\t\t\tif len(resp.Fields) == 0 {\n\t\t\t\treturn fmt.Errorf(\"expecting field event first, got: %v\", resp)\n\t\t\t}\n\n\t\t\tlastpk = nil\n\t\t\t// pkfields are only used for logging, so that we can monitor progress.\n\t\t\tpkfields = make([]*querypb.Field, 0, len(resp.Pkfields))\n\t\t\tfor _, f := range resp.Pkfields {\n\t\t\t\tpkfields = append(pkfields, f.CloneVT())\n\t\t\t}\n\n\t\t\tfieldEvent := &binlogdatapb.FieldEvent{\n\t\t\t\tTableName: tableName,\n\t\t\t}\n\t\t\tfor _, f := range resp.Fields {\n\t\t\t\tfieldEvent.Fields = append(fieldEvent.Fields, f.CloneVT())\n\t\t\t}\n\t\t\ttablePlan, err := state.plan.buildExecutionPlan(fieldEvent)\n\t\t\tif err != nil {\n\t\t\t\treturn err","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/vcopier_atomic.go#L146-L182","documentation":"In vcopier_atomic (atomic copy mode), when the copy queue for a table is not open the code expects the response to carry field metadata (resp.Fields). If a rows response arrives with no fields, the copier cannot decode the rows and returns 'expecting field event first'. It is the atomic-mode counterpart of the vcopier.go:494 error.","triggerScenarios":"copyNext (atomic path) receives a rows response for a table whose queue is closed/just-opened and resp.Fields is empty — the field event for the table was never delivered or was lost before rows.","commonSituations":"Atomic copy resuming after controller restart with lost cached schema; source sending rows for a table before its field event; binlog stream misordering or schema-cache eviction.","solutions":["Restart the VReplication workflow so the copy phase re-receives field events from the start","Check earlier logs for failures fetching field info for the table","Verify the source table schema is readable and unchanged during copy","Retry the copy phase; if reproducible, report with the GTID/binlog position"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := vc.copyNext(ctx); err != nil {\n  if strings.Contains(err.Error(), \"expecting field event first\") {\n    // restart the atomic copy phase so field events are re-delivered\n  }\n  return err\n}","preventionTips":["Avoid controller restarts mid-atomic-copy; restart the full phase instead","Keep source schema stable during copy","Monitor logs for field-info fetch failures before row streaming begins"],"tags":["vreplication","vcopier-atomic","binlog","field-event"],"backgroundTag":"missing-field-event-before-rows","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}