{"record":{"id":"c57a189c4c11e11d","repo":"vitessio/vitess","slug":"enum-or-set-column-s-does-not-have-valid-string-v","errorCode":null,"errorMessage":"enum or set column %s does not have valid string values: %q; the column's type definition is unavailable -- this usually means the column was dropped, and decoding historical rows for a dropped ENUM/SET column requires --track-schema-versions with a schema version retained from while the column still existed","messagePattern":"enum or set column (.+?) does not have valid string values: %q; the column's type definition is unavailable -- this usually means the column was dropped, and decoding historical rows for a dropped ENUM/SET column requires --track-schema-versions with a schema version retained from while the column still existed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletserver/vstreamer/vstreamer.go","lineNumber":1408,"sourceCode":"\n// addEnumAndSetMappingstoPlan sets up any necessary ENUM and SET integer to string mappings.\nfunc addEnumAndSetMappingstoPlan(env *vtenv.Environment, plan *Plan, cols []*querypb.Field, metadata []uint16) error {\n\tplan.EnumSetValuesMap = make(map[int]map[int]string)\n\tfor i, col := range cols {\n\t\t// If the column is a CHAR based type with a binary collation (e.g. utf8mb4_bin) then\n\t\t// the actual column type is included in the second byte of the event metadata while\n\t\t// the event's type for the field is BINARY. This is true for ENUM and SET types.\n\t\tvar mysqlType uint16\n\t\tif sqltypes.IsQuoted(col.Type) {\n\t\t\tmysqlType = metadata[i] >> 8\n\t\t}\n\t\tif col.Type == querypb.Type_ENUM || mysqlType == mysqlbinlog.TypeEnum ||\n\t\t\tcol.Type == querypb.Type_SET || mysqlType == mysqlbinlog.TypeSet {\n\t\t\t// Strip the enum() / set() parts out.\n\t\t\tbegin := strings.Index(col.ColumnType, \"(\")\n\t\t\tend := strings.LastIndex(col.ColumnType, \")\")\n\t\t\tif begin == -1 || end == -1 {\n\t\t\t\treturn fmt.Errorf(\"enum or set column %s does not have valid string values: %q; \"+\n\t\t\t\t\t\"the column's type definition is unavailable -- this usually means the column \"+\n\t\t\t\t\t\"was dropped, and decoding historical rows for a dropped ENUM/SET column \"+\n\t\t\t\t\t\"requires --track-schema-versions with a schema version retained from while \"+\n\t\t\t\t\t\"the column still existed\", col.Name, col.ColumnType)\n\t\t\t}\n\t\t\tvar err error\n\t\t\tplan.EnumSetValuesMap[i], err = vtschema.ParseEnumOrSetTokensMap(env, col.ColumnType[begin+1:end])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// buildEnumStringValue takes the integer value of an ENUM column and returns the string value.\nfunc buildEnumStringValue(env *vtenv.Environment, plan *streamerPlan, colNum int, value sqltypes.Value) (sqltypes.Value, error) {\n\tif value.IsNull() { // No work is needed","sourceCodeStart":1390,"sourceCodeEnd":1426,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go#L1390-L1426","documentation":"To decode ENUM/SET values, vstreamer needs the string value list from the column's ColumnType (e.g. enum('a','b')). If the parentheses delimiting the value list are missing — meaning the type definition is unavailable, typically because the column was dropped — the historical row cannot be decoded and this actionable error is returned pointing to --track-schema-versions.","triggerScenarios":"addEnumAndSetMappingstoPlan finds col.Type is ENUM or SET (or the binlog type is TypeEnum/TypeSet) but strings.Index/LastIndex of '(' and ')' in col.ColumnType return -1, so no value list can be extracted.","commonSituations":"Replaying old binlog rows for a table whose ENUM/SET column was since dropped; minimal schema (no full column types) cached for the table; missing --track-schema-versions history for the pre-DROP definition.","solutions":["Enable --track-schema-versions and retain the schema version captured while the ENUM/SET column still existed","Restore the column (re-add it with the same definition) if the historical rows must be decoded","Rebuild the table/re-copy data so old rows no longer need the dropped column's definition","Skip or reposition the stream past events written before the column was dropped"],"exampleFix":"// before (vttablet flags)\nvttablet ... # no schema version tracking\n// after\nvttablet ... --track-schema-versions","handlingStrategy":"validation","validationCode":"// Confirm the column's type definition is retained:\n// SELECT column_type FROM information_schema.columns\n//  WHERE table_name='<t>' AND column_name='<c>'; -- must contain enum(...)/set(...)\n// Enable --track-schema-versions on vttablet for historical decode.","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"does not have valid string values\") {\n    // enable/retain --track-schema-versions with the pre-DROP schema version, or skip past the dropped-column rows\n}","preventionTips":["Enable --track-schema-versions before doing DDL on replicated tables","Retain schema versions covering your vreplication retention window","Avoid dropping ENUM/SET columns while historical streams are active"],"tags":["enum","set","schema-history","dropped-column","vstreamer"],"backgroundTag":"enum-set-type-definition-missing","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}