vitessio/vitess · error

too many .s

Error message

too many .s

What it means

parseDecimal64 rejects digit strings containing more than one '.' because a decimal literal may have at most one decimal point; a second '.' makes the string invalid MySQL decimal syntax. NewFromMySQL surfaces this when decoding a value from the wire protocol.

Source

Thrown at go/mysql/decimal/scan.go:43

	"math/bits"
	"strings"

	"vitess.io/vitess/go/mysql/fastparse"
)

var errOverflow = errors.New("overflow")

func parseDecimal64(s []byte) (Decimal, error) {
	const cutoff = math.MaxUint64/10 + 1
	var n uint64
	dot := -1

	for i, c := range s {
		var d byte
		switch {
		case c == '.':
			if dot > -1 {
				return Decimal{}, errors.New("too many .s")
			}
			dot = i
			continue
		case '0' <= c && c <= '9':
			d = c - '0'
		default:
			return Decimal{}, fmt.Errorf("unexpected character %q", c)
		}

		if n >= cutoff {
			// n*base overflows
			return Decimal{}, errOverflow
		}
		n *= 10
		n1 := n + uint64(d)
		if n1 < n {
			return Decimal{}, errOverflow
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Sanitize/normalize the decimal string before parsing: keep only the first '.' and drop or reject subsequent ones
  2. Fix the producer that emits malformed decimals so it never concatenates fractional parts
  3. Validate input with a regex like ^-?\d*(\.\d+)?$ before handing it to the decimal parser

Example fix

// before
dec, err := decimal.NewFromMySQL([]byte("1.2.3")) // "too many .s"
// after
s := strings.Replace(raw, ".", "", 1) // or validate first
dec, err := decimal.NewFromMySQL([]byte(s))
Defensive patterns

Strategy: validation

Validate before calling

var decimalRe = regexp.MustCompile(`^-?\d*(\.\d+)?$`)
if !decimalRe.Match(raw) { return fmt.Errorf("invalid decimal %q", raw) }

Type guard

func isWellFormedDecimal(s []byte) bool {
    return bytes.Count(s, []byte{"."}) <= 1
}

Try / catch

dec, err := decimal.NewFromMySQL(raw)
if err != nil && strings.Contains(err.Error(), "too many .s") {
    return normalizeDecimal(raw) // keep only first '.'
}

Prevention

When it happens

Trigger: parseDecimal64 iterating a byte slice that already recorded a dot position (dot > -1) and encounters another '.' character.

Common situations: Corrupted or hand-crafted wire data; upstream code that concatenated numbers (e.g. "1.2" + ".3"); locale formatting where ',' and '.' are mixed; bugs in code building decimal strings manually.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/7ad8f4b0c56bb069. Report an issue: GitHub.