vitessio/vitess · error
internal error: unexpected rows without fields
Error message
internal error: unexpected rows without fields
What it means
messager's processRowEvent requires the field metadata that accompanies row events; row changes cannot be interpreted without it. This error is marked "Unreachable" in code — it's an invariant check that fires only if a RowEvent arrives with nil fields, which should be impossible from the VStream protocol.
Source
Thrown at go/vt/vttablet/tabletserver/messager/message_manager.go:755
case binlogdatapb.VEventType_COMMIT, binlogdatapb.VEventType_DDL, binlogdatapb.VEventType_OTHER:
// Update curPos only when the GTID concludes, which is through one
// of the above events.
curPos = newPos
skipEvents, err = mustSkip()
if err != nil {
return err
}
}
}
return nil
}, nil)
return err
}
func (mm *messageManager) processRowEvent(fields []*querypb.Field, rowEvent *binlogdatapb.RowEvent) error {
if fields == nil {
// Unreachable.
return errors.New("internal error: unexpected rows without fields")
}
now := time.Now().UnixNano()
for _, rc := range rowEvent.RowChanges {
if rc.After == nil {
continue
}
row := sqltypes.MakeRowTrusted(fields, rc.After)
mr, err := BuildMessageRow(row)
if err != nil {
return err
}
if mr.TimeAcked != 0 || mr.TimeNext > now {
continue
}
mm.Add(mr)
}
return nilView on GitHub (pinned to 01a25a7d17)
Solutions
- This indicates an internal bug — file an issue with vttablet logs and the binlog event sequence around the failure
- Check for intermediate vstream consumers/proxies between source and messager that may drop FieldEvent messages
- Restart the vreplication stream/messager to re-establish fields; if reproducible, capture the VStream events with a debug client
Defensive patterns
Strategy: try-catch
Try / catch
if err := mm.processRowEvent(fields, rowEvent); err != nil {
if strings.Contains(err.Error(), "unexpected rows without fields") {
// protocol bug: capture diagnostics and restart the stream
log.Error("row event arrived without field metadata; restarting stream", slog.Any("error", err))
return restartStream(ctx)
}
return err
} Prevention
- Don't insert custom VStream consumers that drop FieldEvent messages
- Keep Vitess components on compatible versions (no mixed old/new vstreaming)
- Report reproducible occurrences with full vttablet logs — this is an internal invariant violation
When it happens
Trigger: processRowEvent is invoked with fields == nil — i.e. a binlogdatapb.RowEvent is delivered through the message stream without its associated field metadata, indicating a protocol bug.
Common situations: VReplication/VStream bugs where FieldEvents were dropped or reordered; custom vstream clients or middlemen stripping field events; corrupted stream relay logic.
Related errors
- got a real event before FORMAT_DESCRIPTION_EVENT: %#v
- unexpected: query ended without no results and no error
- GetPreviousGTIDs: previous GTIDs not found
- Log file number is zero, cannot detect previous file
- unexpected: there are no tables to copy
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/b6c1aa963f32021b.
Report an issue: GitHub.