vitessio/vitess · error

can't convert %q to decimal: too short

Error message

can't convert %q to decimal: too short

What it means

NewFromMySQL rejects an empty decimal payload. After an optional leading sign is stripped, if no characters remain there is nothing to parse, so it returns this error quoting the original input. This guards against empty binary strings or a bare sign like "-".

Source

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

	return int32(totalLen - 1), int32(totalLen - 1 - idx)
}

func NewFromMySQL(s []byte) (Decimal, error) {
	original := s
	var neg bool

	if len(s) > 0 {
		switch s[0] {
		case '+':
			s = s[1:]
		case '-':
			neg = true
			s = s[1:]
		}
	}

	if len(s) == 0 {
		return Decimal{}, fmt.Errorf("can't convert %q to decimal: too short", original)
	}

	if len(s) <= 18 {
		dec, err := parseDecimal64(s)
		if err == nil {
			if neg {
				dec.value.Neg(dec.value)
			}
			return dec, nil
		}
		if err != errOverflow {
			return Decimal{}, fmt.Errorf("can't convert %s to decimal: %v", original, err)
		}
	}

	var fractional, integral []byte
	if pIndex := bytes.IndexByte(s, '.'); pIndex >= 0 {
		if bytes.IndexByte(s[pIndex+1:], '.') != -1 {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check the caller and fix the source so it never produces an empty or sign-only decimal payload.
  2. Add a length check on the wire data before calling NewFromMySQL and handle empty values explicitly (e.g. treat as NULL or zero).
  3. If a zero value is acceptable for empty input, default to NewFromMySQL([]byte("0")) at the call site.

Example fix

// before
dec, err := NewFromMySQL(data)

// after
if len(bytes.Trim(data, "+-")) == 0 {
    dec, err = NewFromMySQL([]byte("0"))
} else {
    dec, err = NewFromMySQL(data)
}
Defensive patterns

Strategy: validation

Validate before calling

if len(bytes.Trim(data, "+-")) == 0 {
    return fmt.Errorf("refusing to parse empty decimal payload")
}

Try / catch

dec, err := decimal.NewFromMySQL(data)
if err != nil {
    if strings.Contains(err.Error(), "too short") {
        dec, err = decimal.NewFromMySQL([]byte("0")) // or treat as NULL
    }
}

Prevention

When it happens

Trigger: Calling NewFromMySQL with a zero-length byte slice, or a slice containing only a '-' or '+' sign (the sign is stripped, leaving len(s)==0).

Common situations: A column value truncated to empty by a misbehaving sender; hand-written serialization code writing a sign but no digits; fuzz tests or adversarial clients feeding empty DECIMAL payloads.

Related errors


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