{"record":{"id":"d17a1ed41bd2212b","repo":"vitessio/vitess","slug":"unparsed-tail-left-after-parsing-int64-from-q-q","errorCode":null,"errorMessage":"unparsed tail left after parsing int64 from %q: %q","messagePattern":"unparsed tail left after parsing int64 from %q: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"go/mysql/fastparse/fastparse.go","lineNumber":233,"sourceCode":"\t\tif d == math.MaxInt64+1 {\n\t\t\tv = math.MinInt64\n\t\t}\n\t}\n\n\tif i <= j {\n\t\treturn v, fmt.Errorf(\"cannot parse int64 from %q\", s)\n\t}\n\n\tfor i < uint(len(s)) {\n\t\tif !isSpace(s[i]) {\n\t\t\tbreak\n\t\t}\n\t\ti++\n\t}\n\n\tif i < uint(len(s)) {\n\t\t// Unparsed tail left.\n\t\treturn v, fmt.Errorf(\"unparsed tail left after parsing int64 from %q: %q\", s, s[i:])\n\t}\n\tif d == math.MaxInt64+1 && minus {\n\t\tv = math.MinInt64\n\t}\n\n\treturn v, nil\n}\n\n// ParseFloat64 parses floating-point number s.\n//\n// It is equivalent to strconv.ParseFloat(s, 64) in case it succeeds,\n// but on error it will return the best effort value of what it has parsed so far.\nfunc ParseFloat64(s string) (float64, error) {\n\tif len(s) == 0 {\n\t\treturn 0.0, errors.New(\"cannot parse float64 from empty string\")\n\t}\n\ti := uint(0)\n\tfor i < uint(len(s)) {","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/fastparse/fastparse.go#L215-L251","documentation":"ParseInt64 parses the leading digits successfully but finds trailing characters that are neither digits nor space/tab (space/tab are consumed as trailing whitespace). It returns the parsed value together with this error identifying the unconsumed tail. This matches MySQL's lenient '123abc' -> 123 coercion semantics while still signalling the problem.","triggerScenarios":"ParseInt64(\"123abc\", 10), ParseInt64(\"12.5\", 10) (the '.' stops digit parsing), or \"0x1F\" parsed with base 10.","commonSituations":"String-to-int SQL coercions of mixed content, CSV fields with stray characters or units (\"42ms\"), decimal literals wrongly routed to integer parsing.","solutions":["Treat the error as invalid input and reject, unless MySQL-style truncation semantics are desired.","Route strings containing '.' or 'e' to fastparse.ParseFloat64 instead.","Trim/clean the input (strip units, split on delimiters) before integer parsing."],"exampleFix":"// before\nv, err := fastparse.ParseInt64(s, 10)\n// after\nv, err := fastparse.ParseInt64(s, 10)\nif err != nil && strings.Contains(err.Error(), \"unparsed tail\") {\n    return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"trailing characters in integer literal %q\", s)\n}","handlingStrategy":"validation","validationCode":"var intRe = regexp.MustCompile(`^-?[0-9]+$`)\n\nfunc strictInt64(s string) (int64, error) {\n    if !intRe.MatchString(strings.TrimSpace(s)) {\n        return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"not a plain integer: %q\", s)\n    }\n    return fastparse.ParseInt64(s, 10)\n}","typeGuard":null,"tryCatchPattern":"v, err := fastparse.ParseInt64(s, 10)\nif err != nil {\n    // parsed value v is prefix-only; do not use unless truncation is intended\n    return 0, vterrors.Wrapf(err, vtrpcpb.Code_INVALID_ARGUMENT, \"integer literal %q has trailing characters\", s)\n}","preventionTips":["Only rely on the truncated value when MySQL truncation semantics are explicitly wanted.","Route decimal-looking strings ('.', 'e') to ParseFloat64 instead.","Strip units/suffixes before parsing numeric fields from external data."],"tags":["parsing","int64","trailing-characters"],"backgroundTag":"number-parse-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}