vitessio/vitess · error

filter rules are not supported for SBR replication: %v

Error message

filter rules are not supported for SBR replication: %v

What it means

VReplication supports row-based replication (RBR) filtering via the workflow's Filter rules. When the source stream is statement-based replication (SBR) events (VEventType_STMT), row-filter rules cannot be applied, so vplayer refuses the event and errors out rather than silently replicating unfiltered or incorrectly filtered statements.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/vplayer.go:360

		}
		return err
	}
}

// applyStmtEvent applies an actual DML statement received from the source, directly onto the backend database
func (vp *vplayer) applyStmtEvent(ctx context.Context, event *binlogdatapb.VEvent) error {
	sql := event.Statement
	if sql == "" {
		sql = event.Dml
	}
	if event.Type == binlogdatapb.VEventType_SAVEPOINT || vp.canAcceptStmtEvents {
		start := time.Now()
		_, err := vp.query(ctx, sql)
		vp.vr.stats.QueryTimings.Record(vp.phase, start)
		vp.vr.stats.QueryCount.Add(vp.phase, 1)
		return err
	}
	return fmt.Errorf("filter rules are not supported for SBR replication: %v", vp.vr.source.Filter.GetRules())
}

// bulkApplicableShapes scans a row event's changes and reports whether they
// are all delete-shaped (Before image only) or all insert-shaped (After image
// only). A single event can mix shapes: when only one side of an update passes
// the source vstreamer's workflow filter (e.g. a sharding-key update that
// moves rows across an in_keyrange boundary), only that side's image is
// emitted, so one multi-row UPDATE can yield insert-shaped, delete-shaped and
// update-shaped changes in the same event. The bulk DELETE/INSERT statements
// assume a homogeneous event, so a mixed event must be applied per-change.
// A change with no images at all (nil, or present but empty) is malformed --
// the vstreamer never produces one -- and is rejected with an error rather
// than being routed to either apply path: the per-change path would
// dereference a nil change and silently treat an empty one as a no-op.
// The scan visits every change, even once the event is already known not to
// be bulk-applicable, so a malformed entry is detected regardless of its
// position.
func bulkApplicableShapes(tableName string, rowChanges []*binlogdatapb.RowChange) (deletesOnly, insertsOnly bool, err error) {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Set binlog_format=ROW on the source MySQL cluster and restart replication before/while vstreaming
  2. Verify the source's binlog format with SHOW VARIABLES LIKE 'binlog_format' and ensure it persists in my.cnf
  3. Re-create/restart the vreplication workflow after switching the source to ROW format
  4. If you genuinely need SBR with filters, remove filter rules or redesign the workflow — the combination is unsupported

Example fix

// before (source my.cnf)
binlog_format = STATEMENT
// after
binlog_format = ROW
Defensive patterns

Strategy: validation

Validate before calling

// Verify the source uses ROW binlog format before starting a filtered workflow
row, err := db.Query("SHOW VARIABLES LIKE 'binlog_format'")
// fail fast if value != "ROW"

Try / catch

if err != nil && strings.Contains(err.Error(), "filter rules are not supported for SBR") {
    // switch source to binlog_format=ROW, then restart the workflow
}

Prevention

When it happens

Trigger: applyStmtEvent is reached with vp.vr.source.Filter containing rules while the source binlog stream is in statement-based mode (binlog_format=STATEMENT or MIXED producing statement events on the vstream).

Common situations: Source MySQL cluster configured with binlog_format=STATEMENT or MIXED; source downgrade or a MySQL flavor that reverted to SBR; workflow set up expecting RBR but source not in ROW format.

Related errors


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