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 nil

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. This indicates an internal bug — file an issue with vttablet logs and the binlog event sequence around the failure
  2. Check for intermediate vstream consumers/proxies between source and messager that may drop FieldEvent messages
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/b6c1aa963f32021b. Report an issue: GitHub.