If you ALTER a table to DROP an ENUM column, a vstream can fail to process older binlog events even when schema version tracking (--track-schema-versions) is enabled.
git checkout main && make build
cat <<'EOF'>/tmp/bug-test-case-diff.txt
diff --git a/examples/common/scripts/vttablet-up.sh b/examples/common/scripts/vttablet-up.sh
index 8ccd8bbea1..5d273df6ed 100755
--- a/examples/common/scripts/vttablet-up.sh
+++ b/examples/common/scripts/vttablet-up.sh
@@ -55,6 +55,7 @@ vttablet \
--heartbeat-on-demand-duration=5s \
--pprof-http \
--log-format text \
+ ${VTTABLET_EXTRA_FLAGS:-} \
>$VTDATAROOT/$tablet_dir/vttablet.out 2>&1 &
# Block waiting for the tablet to be listening
diff --git a/examples/local/vstream_client_enum_repro.go b/examples/local/vstream_client_enum_repro.go
new file mode 100644
index 0000000000..4d671fc74b
--- /dev/null
+++ b/examples/local/vstream_client_enum_repro.go
@@ -0,0 +1,116 @@
+/*
+Copyright 2026 The Vitess Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "time"
+
+ _ "vitess.io/vitess/go/vt/vtctl/grpcvtctlclient"
+ _ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
+ "vitess.io/vitess/go/vt/vtgate/vtgateconn"
+
+ binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
+ topodatapb "vitess.io/vitess/go/vt/proto/topodata"
+ vtgatepb "vitess.io/vitess/go/vt/proto/vtgate"
+)
+
+// vstream_client_enum_repro reproduces the upstream Vitess bug where
+// vstream cannot decode an ENUM column whose column has been dropped
+// between the cursor position and the live schema.
+//
+// Two modes (selected by the VSTREAM_CURSOR_GTID env var):
+//
+// 1. Capture: when VSTREAM_CURSOR_GTID is unset, the client streams
+// from the current position, waits for the first VGTID event, prints it,
+// and exits. The printed VGTID is the resume point to use for mode 2.
+//
+// 2. Resume: when VSTREAM_CURSOR_GTID is set (format: "MySQL56/<uuid>:1-N"),
+// the client streams from that position. After the ALTER TABLE
+// DROP COLUMN, vstream replays the older INSERTs, hits the empty
+// ColumnType in addEnumAndSetMappingstoPlan, and fails with
+// "enum or set column pricing_scheme does not have valid string values".
+func main() {
+ cursorGTID := os.Getenv("VSTREAM_CURSOR_GTID")
+ startGTID := cursorGTID
+ if startGTID == "" {
+ startGTID = "current"
+ }
+
+ ctx := context.Background()
+ vgtid := &binlogdatapb.VGtid{
+ ShardGtids: []*binlogdatapb.ShardGtid{{
+ Keyspace: "commerce",
+ Shard: "0",
+ Gtid: startGTID,
+ }},
+ }
+ filter := &binlogdatapb.Filter{
+ Rules: []*binlogdatapb.Rule{{
+ Match: "enum_repro",
+ Filter: "select * from enum_repro",
+ }},
+ FieldEventMode: binlogdatapb.Filter_ERR_ON_MISMATCH,
+ }
+
+ conn, err := vtgateconn.Dial(ctx, "localhost:15991")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer conn.Close()
+
+ flags := &vtgatepb.VStreamFlags{}
+ reader, err := conn.VStream(ctx, topodatapb.TabletType_PRIMARY, vgtid, filter, flags)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ captureMode := cursorGTID == ""
+ if captureMode {
+ fmt.Println("CAPTURE MODE: waiting for first VGTID event...")
+ } else {
+ fmt.Printf("RESUME MODE: streaming from %s\n", cursorGTID)
+ }
+
+ for {
+ evs, err := reader.Recv()
+ switch err {
+ case nil:
+ for _, ev := range evs {
+ if captureMode && ev.Type == binlogdatapb.VEventType_VGTID {
+ for _, sg := range ev.Vgtid.ShardGtids {
+ fmt.Printf("CAPTURED VGTID: keyspace=%s shard=%s gtid=%s\n",
+ sg.Keyspace, sg.Shard, sg.Gtid)
+ fmt.Printf("export VSTREAM_CURSOR_GTID='%s'\n", sg.Gtid)
+ }
+ return
+ }
+ fmt.Printf("%v\n", ev)
+ }
+ case io.EOF:
+ fmt.Printf("stream ended\n")
+ return
+ default:
+ fmt.Printf("%s:: remote error: %v\n", time.Now(), err)
+ return
+ }
+ }
+}
EOF
git apply /tmp/bug-test-case-diff.txt
cd examples/local
source ../common/env.sh
export VTTABLET_EXTRA_FLAGS='--track-schema-versions --schema-version-max-age-seconds=7776000' SKIP_VTADMIN=1
./101_initial_cluster.sh
command mysql --no-defaults -h 127.0.0.1 -P 15306 --binary-as-hex=false <<'SQL'
DROP TABLE IF EXISTS enum_repro;
CREATE TABLE enum_repro (
id bigint NOT NULL,
pricing_scheme enum('free', 'standard', 'enterprise') NOT NULL,
note varchar(128) NOT NULL,
PRIMARY KEY (id)
);
SQL
until command mysql --no-defaults -h 127.0.0.1 -P 15306 --binary-as-hex=false commerce:0 -Nse \
"select count(*) from _vt.schema_version where ddl like '%enum_repro%'" | grep -q '^[1-9]'; do
sleep 1
done
unset VSTREAM_CURSOR_GTID
go run ./vstream_client_enum_repro.go
command mysql --no-defaults -h 127.0.0.1 -P 15306 --binary-as-hex=false <<'SQL'
INSERT INTO enum_repro(id, pricing_scheme, note) VALUES
(1, 'free', 'before drop'),
(2, 'enterprise', 'before drop');
ALTER TABLE enum_repro DROP COLUMN pricing_scheme;
SQL
go run ./vstream_client_enum_repro.go
go run ./vstream_client_enum_repro.go
RESUME MODE: streaming from MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-44
type:BEGIN timestamp:1779591484 current_time:1779591553275772000 keyspace:"commerce" shard:"0" commit_parent:44 sequence_number:45 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:45"
type:VGTID vgtid:{shard_gtids:{keyspace:"commerce" shard:"0" gtid:"MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-45"}} keyspace:"commerce" shard:"0"
type:COMMIT timestamp:1779591484 current_time:1779591553275782000 keyspace:"commerce" shard:"0" commit_parent:44 sequence_number:45 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:45"
type:BEGIN timestamp:1779591485 current_time:1779591553275792000 keyspace:"commerce" shard:"0" commit_parent:45 sequence_number:46 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:46"
type:VGTID vgtid:{shard_gtids:{keyspace:"commerce" shard:"0" gtid:"MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-46"}} keyspace:"commerce" shard:"0"
type:COMMIT timestamp:1779591485 current_time:1779591553275797000 keyspace:"commerce" shard:"0" commit_parent:45 sequence_number:46 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:46"
type:BEGIN timestamp:1779591486 current_time:1779591553275806000 keyspace:"commerce" shard:"0" commit_parent:46 sequence_number:47 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:47"
type:VGTID vgtid:{shard_gtids:{keyspace:"commerce" shard:"0" gtid:"MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-47"}} keyspace:"commerce" shard:"0"
type:COMMIT timestamp:1779591486 current_time:1779591553275813000 keyspace:"commerce" shard:"0" commit_parent:46 sequence_number:47 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:47"
type:BEGIN timestamp:1779591487 current_time:1779591553275821000 keyspace:"commerce" shard:"0" commit_parent:47 sequence_number:48 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:48"
type:VGTID vgtid:{shard_gtids:{keyspace:"commerce" shard:"0" gtid:"MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-48"}} keyspace:"commerce" shard:"0"
type:COMMIT timestamp:1779591487 current_time:1779591553275828000 keyspace:"commerce" shard:"0" commit_parent:47 sequence_number:48 event_gtid:"5cb3b178-571c-11f1-9925-d8830bab3b24:48"
2026-05-24 02:59:13.287359 +0000 UTC m=+0.059699876:: remote error: Code: UNKNOWN
rpc error: code = Unknown desc = error starting stream from shard GTID keyspace:"commerce" shard:"0" gtid:"MySQL56/5cb3b178-571c-11f1-9925-d8830bab3b24:1-48": persistent error in vstream for commerce/0 on tablet zone1-0000000100; giving up: target: commerce.0.primary: vttablet: rpc error: code = Unknown desc = stream (at source tablet) error @ (including the GTID we failed to process) 5cb3b178-571c-11f1-9925-d8830bab3b24:1-49: enum or set column pricing_scheme does not have valid string values:
failed to build ENUM and SET column integer to string mappings
failed to build table replication plan for table enum_repro
Overview of the Issue
If you ALTER a table to DROP an ENUM column, a vstream can fail to process older binlog events even when schema version tracking (
--track-schema-versions) is enabled.Reproduction Steps
Cut and paste the printed
export VSTREAM_CURSOR_GTID='...'line.The Final Results
Binary Version
❯ vtgate --version vtgate version Version: 25.0.0-SNAPSHOT (Git revision c08871ee9a103424a22c5bd5919572e45be66377 branch 'main') built on Fri May 15 19:51:50 UTC 2026 by matt@pslord.local using go1.26.3 darwin/arm64Operating System and Environment details
Log Fragments