{"record":{"id":"f01045a8b33a9dcd","repo":"vitessio/vitess","slug":"unreachable-f01045","errorCode":null,"errorMessage":"unreachable","messagePattern":"unreachable","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval_numeric.go","lineNumber":282,"sourceCode":"\t\t\tswitch e.NumberType() {\n\t\t\tcase json.NumberTypeSigned:\n\t\t\t\ti, _ := e.Int64()\n\t\t\t\treturn newEvalDecimal(decimal.NewFromInt(i), m, d)\n\t\t\tcase json.NumberTypeUnsigned:\n\t\t\t\t// If the value fits in an unsigned integer, convert to that\n\t\t\t\t// and then cast it to a signed integer and then turn it into a decimal.\n\t\t\t\t// SELECT CAST(CAST(18446744073709551615 AS JSON) AS DECIMAL) -> -1\n\t\t\t\tu, _ := e.Uint64()\n\t\t\t\treturn newEvalDecimal(decimal.NewFromInt(int64(u)), m, d)\n\t\t\tcase json.NumberTypeDecimal:\n\t\t\t\tdec, _ := e.Decimal()\n\t\t\t\treturn newEvalDecimal(dec, m, d)\n\t\t\tcase json.NumberTypeFloat:\n\t\t\t\tf, _ := e.Float64()\n\t\t\t\tdec := decimal.NewFromFloat(f)\n\t\t\t\treturn newEvalDecimal(dec, m, d)\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\tcase json.TypeString:\n\t\t\tdec, _ := decimal.NewFromString(e.Raw())\n\t\t\treturn newEvalDecimal(dec, m, d)\n\t\tdefault:\n\t\t\treturn newEvalDecimal(decimal.Zero, m, d)\n\t\t}\n\tcase *evalTemporal:\n\t\treturn newEvalDecimal(e.toDecimal(), m, d)\n\tcase *evalEnum:\n\t\treturn newEvalDecimal(decimal.NewFromInt(enumNumeric(e.value)), m, d)\n\tcase *evalSet:\n\t\treturn newEvalDecimal(decimal.NewFromUint(e.set), m, d)\n\tdefault:\n\t\tpanic(\"unsupported\")\n\t}\n}\n","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval_numeric.go#L264-L300","documentation":"Inside evalToDecimal, when converting an evalJSON value, the code switches on the JSON number kind. Any NumberType other than Int/Uint/Float hits the default branch and panics \"unreachable\". It encodes the assumption that JSON numbers only have those three representations.","triggerScenarios":"evalToDecimal receives an *evalJSON whose Number() returns a number type not in {Int, Uint, Float} — e.g. a new json.NumberType added by a library upgrade, or corrupted JSON state.","commonSituations":"Vitess/go-vtupgrades where the json library gained a new NumberType; passing malformed JSON documents through decimal comparison paths (compareAllDecimal, integerDivideConvert).","solutions":["Log/handle the unknown json.NumberType explicitly and treat it like NumberTypeFloat instead of panicking","Check the json package version used; align eval_numeric.go's switch with the current NumberType enum","If reachable via a query, work around by casting the JSON value to a numeric type explicitly in SQL before comparison"],"exampleFix":"// before\ndefault:\n    panic(\"unreachable\")\n// after\ndefault:\n    f, _ := e.Float64()\n    return newEvalDecimal(decimal.NewFromFloat(f), m, d)","handlingStrategy":"validation","validationCode":"nt, _ := jsonVal.Number()\nif nt != json.NumberTypeInt && nt != json.NumberTypeUint && nt != json.NumberTypeFloat {\n    return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"unsupported JSON number type %v\", nt)\n}","typeGuard":"func isKnownJSONNumber(t json.NumberType) bool {\n    switch t {\n    case json.NumberTypeInt, json.NumberTypeUint, json.NumberTypeFloat:\n        return true\n    default:\n        return false\n    }\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, \"evalToDecimal: %v\", r)\n    }\n}()","preventionTips":["After upgrading the json dependency, diff json.NumberType against the switch in eval_numeric.go","Prefer explicit numeric casts in SQL for JSON values before decimal arithmetic","Add a fuzz/unit test converting every NumberType through evalToDecimal"],"tags":["go","panic","evalengine","json"],"backgroundTag":"unreachable-code-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}