{"record":{"id":"b8756ec13743079c","repo":"vitessio/vitess","slug":"bug-sqlparser-emitted-unknown-type","errorCode":null,"errorMessage":"BUG: sqlparser emitted unknown type","messagePattern":"BUG: sqlparser emitted unknown type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/expr_convert.go","lineNumber":152,"sourceCode":"\t\treturn nil, nil\n\tcase \"DATE\":\n\t\tif d := evalToDate(e, env.now, env.sqlmode.AllowZeroDate()); d != nil {\n\t\t\treturn d, nil\n\t\t}\n\t\treturn nil, nil\n\tcase \"TIME\":\n\t\tp := ptr.Unwrap(c.Length, 0)\n\t\tif p > 6 {\n\t\t\treturn nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"Too-big precision %d specified for 'CONVERT'. Maximum is 6.\", p)\n\t\t}\n\t\tif t := evalToTime(e, p); t != nil {\n\t\t\treturn t, nil\n\t\t}\n\t\treturn nil, nil\n\tcase \"YEAR\":\n\t\treturn nil, c.returnUnsupportedError()\n\tdefault:\n\t\tpanic(\"BUG: sqlparser emitted unknown type\")\n\t}\n}\n\nfunc (c *ConvertExpr) convertToBinaryType(tt sqltypes.Type) sqltypes.Type {\n\tif c.Length != nil {\n\t\tif *c.Length > 64*1024 {\n\t\t\treturn sqltypes.Blob\n\t\t}\n\t} else if tt == sqltypes.Blob || tt == sqltypes.TypeJSON {\n\t\treturn sqltypes.Blob\n\t}\n\treturn sqltypes.VarBinary\n}\n\nfunc (c *ConvertExpr) convertToCharType(tt sqltypes.Type) sqltypes.Type {\n\tif c.Length != nil {\n\t\tcol := colldata.Lookup(c.Collation)\n\t\tlength := *c.Length * col.Charset().MaxWidth()","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/expr_convert.go#L134-L170","documentation":"When compiling a CONVERT/CAST expression, the evalengine switches over the target type name sqlparser emitted (CHAR, SIGNED, UNSIGNED, DATE, etc.) and panics if the name is none of the known ones. The message asserts that sqlparser should never produce an unknown conversion type, so this panic indicates a bug in the parser-to-evalengine contract rather than bad user input.","triggerScenarios":"Evaluating a CAST/CONVERT whose target type string from the parsed AST does not match any case in ConvertExpr's switch — e.g., a newly added sqlparser convert type not yet handled, or a hand-built ConvertExpr with a typo'd type name.","commonSituations":"New MySQL cast types added to sqlparser (or Vitess version skew) where evalengine lags; tests constructing ConvertExpr manually; custom forks adding CAST types.","solutions":["Print the offending type name from the AST to identify the unhandled case","Add a case for the new type in ConvertExpr's compile/convert switch in expr_convert.go","Return a proper 'unsupported conversion' error (like the YEAR case does) instead of panicking for legitimately unsupported types","Align sqlparser and evalengine versions"],"exampleFix":"// before\ncase \"YEAR\":\n\treturn nil, c.returnUnsupportedError()\ndefault:\n\tpanic(\"BUG: sqlparser emitted unknown type\")\n// after\ncase \"YEAR\":\n\treturn nil, c.returnUnsupportedError()\ncase \"NEWTYPE\":\n\treturn convertNewType(...)\ndefault:\n\treturn nil, c.returnUnsupportedError() // or keep panic, but handle the new type","handlingStrategy":"validation","validationCode":"// Validate CAST target types against known conversions before issuing the query\nvar castableTypes = map[string]bool{\"CHAR\": true, \"SIGNED\": true, \"UNSIGNED\": true, \"DATE\": true, \"DATETIME\": true, \"TIME\": true, \"BINARY\": true, \"JSON\": true, \"DECIMAL\": true, \"FLOAT\": true, \"DOUBLE\": true}\nfunc isCastable(t string) bool { return castableTypes[strings.ToUpper(t)] }","typeGuard":"func isKnownConvertType(t sqlparser.ConvertType) bool {\n\treturn isCastable(t.Type)\n}","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\terr = fmt.Errorf(\"convert eval panic: %v\", r)\n\t}\n}()","preventionTips":["Restrict CAST/CONVERT usage to types supported by your Vitess version","Handle new sqlparser cast types in expr_convert.go as part of the same upgrade","Prefer returning an unsupported-conversion error over panicking for new types","Test all CAST targets in expression evaluation tests"],"tags":["evalengine","panic","cast","convert","sqlparser"],"backgroundTag":"unhandled-switch-case-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}