{"record":{"id":"23249282c67c62df","repo":"vitessio/vitess","slug":"filter-rules-are-not-supported-for-sbr-replication","errorCode":null,"errorMessage":"filter rules are not supported for SBR replication: %v","messagePattern":"filter rules are not supported for SBR replication: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/vplayer.go","lineNumber":360,"sourceCode":"\t\t}\n\t\treturn err\n\t}\n}\n\n// applyStmtEvent applies an actual DML statement received from the source, directly onto the backend database\nfunc (vp *vplayer) applyStmtEvent(ctx context.Context, event *binlogdatapb.VEvent) error {\n\tsql := event.Statement\n\tif sql == \"\" {\n\t\tsql = event.Dml\n\t}\n\tif event.Type == binlogdatapb.VEventType_SAVEPOINT || vp.canAcceptStmtEvents {\n\t\tstart := time.Now()\n\t\t_, err := vp.query(ctx, sql)\n\t\tvp.vr.stats.QueryTimings.Record(vp.phase, start)\n\t\tvp.vr.stats.QueryCount.Add(vp.phase, 1)\n\t\treturn err\n\t}\n\treturn fmt.Errorf(\"filter rules are not supported for SBR replication: %v\", vp.vr.source.Filter.GetRules())\n}\n\n// bulkApplicableShapes scans a row event's changes and reports whether they\n// are all delete-shaped (Before image only) or all insert-shaped (After image\n// only). A single event can mix shapes: when only one side of an update passes\n// the source vstreamer's workflow filter (e.g. a sharding-key update that\n// moves rows across an in_keyrange boundary), only that side's image is\n// emitted, so one multi-row UPDATE can yield insert-shaped, delete-shaped and\n// update-shaped changes in the same event. The bulk DELETE/INSERT statements\n// assume a homogeneous event, so a mixed event must be applied per-change.\n// A change with no images at all (nil, or present but empty) is malformed --\n// the vstreamer never produces one -- and is rejected with an error rather\n// than being routed to either apply path: the per-change path would\n// dereference a nil change and silently treat an empty one as a no-op.\n// The scan visits every change, even once the event is already known not to\n// be bulk-applicable, so a malformed entry is detected regardless of its\n// position.\nfunc bulkApplicableShapes(tableName string, rowChanges []*binlogdatapb.RowChange) (deletesOnly, insertsOnly bool, err error) {","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/vplayer.go#L342-L378","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Set binlog_format=ROW on the source MySQL cluster and restart replication before/while vstreaming","Verify the source's binlog format with SHOW VARIABLES LIKE 'binlog_format' and ensure it persists in my.cnf","Re-create/restart the vreplication workflow after switching the source to ROW format","If you genuinely need SBR with filters, remove filter rules or redesign the workflow — the combination is unsupported"],"exampleFix":"// before (source my.cnf)\nbinlog_format = STATEMENT\n// after\nbinlog_format = ROW","handlingStrategy":"validation","validationCode":"// Verify the source uses ROW binlog format before starting a filtered workflow\nrow, err := db.Query(\"SHOW VARIABLES LIKE 'binlog_format'\")\n// fail fast if value != \"ROW\"","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"filter rules are not supported for SBR\") {\n    // switch source to binlog_format=ROW, then restart the workflow\n}","preventionTips":["Always set binlog_format=ROW on sources used for VReplication with filter rules","Persist binlog_format in my.cnf so restarts don't revert to STATEMENT/MIXED","Avoid MIXED format, which can emit statement events for non-deterministic statements","Validate source config as part of workflow preflight checks"],"tags":["vreplication","filter-rules","sbr","binlog-format"],"backgroundTag":"sbr-filter-rules-unsupported","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}