vitessio/vitess · warning
unparsed tail left after parsing int64 from %q: %q
Error message
unparsed tail left after parsing int64 from %q: %q
What it means
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.
Source
Thrown at go/mysql/fastparse/fastparse.go:233
if d == math.MaxInt64+1 {
v = math.MinInt64
}
}
if i <= j {
return v, fmt.Errorf("cannot parse int64 from %q", s)
}
for i < uint(len(s)) {
if !isSpace(s[i]) {
break
}
i++
}
if i < uint(len(s)) {
// Unparsed tail left.
return v, fmt.Errorf("unparsed tail left after parsing int64 from %q: %q", s, s[i:])
}
if d == math.MaxInt64+1 && minus {
v = math.MinInt64
}
return v, nil
}
// ParseFloat64 parses floating-point number s.
//
// It is equivalent to strconv.ParseFloat(s, 64) in case it succeeds,
// but on error it will return the best effort value of what it has parsed so far.
func ParseFloat64(s string) (float64, error) {
if len(s) == 0 {
return 0.0, errors.New("cannot parse float64 from empty string")
}
i := uint(0)
for i < uint(len(s)) {View on GitHub (pinned to 01a25a7d17)
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.
Example fix
// before
v, err := fastparse.ParseInt64(s, 10)
// after
v, err := fastparse.ParseInt64(s, 10)
if err != nil && strings.Contains(err.Error(), "unparsed tail") {
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "trailing characters in integer literal %q", s)
} Defensive patterns
Strategy: validation
Validate before calling
var intRe = regexp.MustCompile(`^-?[0-9]+$`)
func strictInt64(s string) (int64, error) {
if !intRe.MatchString(strings.TrimSpace(s)) {
return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "not a plain integer: %q", s)
}
return fastparse.ParseInt64(s, 10)
} Try / catch
v, err := fastparse.ParseInt64(s, 10)
if err != nil {
// parsed value v is prefix-only; do not use unless truncation is intended
return 0, vterrors.Wrapf(err, vtrpcpb.Code_INVALID_ARGUMENT, "integer literal %q has trailing characters", s)
} Prevention
- 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.
When it happens
Trigger: ParseInt64("123abc", 10), ParseInt64("12.5", 10) (the '.' stops digit parsing), or "0x1F" parsed with base 10.
Common situations: String-to-int SQL coercions of mixed content, CSV fields with stray characters or units ("42ms"), decimal literals wrongly routed to integer parsing.
Related errors
- cannot parse int64 from %q: %w
- unparsed tail left after parsing float64 from %q: %q
- invalid int64 value for %v: %v
- stray %% at the end of pattern
- overflow
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/d17a1ed41bd2212b.
Report an issue: GitHub.