go-sql-driver/mysql · error

not [0-9]

Error message

not [0-9]

What it means

Returned by bToi (utils.go:225) when a byte is outside the ASCII range '0'..'9'. bToi is the low-level digit parser used by parseByteYear, parseByte2Digits and parseByteNanoSec, which in turn feed parseDateTime / parseBinaryDateTime when decoding DATE/DATETIME/TIMESTAMP values received from the server.

Solutions

  1. Inspect the actual bytes in the offending column (SELECT HEX(col)) to confirm corruption vs. misinterpretation.
  2. If the data is genuinely text, store/retrieve it as a string and parse with time.Parse yourself.
  3. Repair or reload the corrupted rows; validate at insert time to prevent recurrence.
  4. Ensure you are talking to a standards-compliant MySQL/MariaDB server, not a mangling proxy.

Example fix

// before: column `d` holds malformed bytes; driver fails decoding
var t time.Time
row.Scan(&t) // -> "not [0-9]"

// after: read raw and parse defensively
var raw string
row.Scan(&raw)
t, err := time.ParseInLocation("2006-01-02 15:04:05", raw, time.UTC)
if err != nil { /* handle */ }
Defensive patterns

Strategy: fallback

Validate before calling

// Scan temporal columns into a string first so corrupt encodings are
// observable rather than fatal.
var raw sql.NullString
if err := rows.Scan(&raw); err != nil { /* handle */ }
t, err := time.ParseInLocation("2006-01-02 15:04:05", raw.String, loc)

Type guard

func isNotDigitParse(err error) bool {
    return err != nil && strings.Contains(err.Error(), "not [0-9]")
}

Try / catch

var t time.Time
if err := rows.Scan(&t); err != nil && isNotDigitParse(err) {
    // column held non-numeric datetime bytes: scan as raw and parse
    // defensively, or flag the row for repair.
}

Prevention

When it happens

Trigger: Decoding a textual or binary temporal value whose digit fields contain non-numeric bytes — corrupted row data, a column reinterpreted as the wrong type, or data produced by a non-conformant server/proxy that mangled the datetime wire format.

Common situations: Reading a DATE/DATETIME column that was actually stored as malformed text; corrupt pages; a custom MySQL fork emitting non-standard datetime encodings; proxy rewriting payloads.

Related errors


AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07). Data as JSON: /api/errors/e674c43ac7ae2dd9. Report an issue: GitHub.

Appendix: source

Thrown at utils.go:225

func parseByteNanoSec(b []byte) (int, error) {
	ns, digit := 0, 100000 // max is 6-digits
	for i := range b {
		v, err := bToi(b[i])
		if err != nil {
			return 0, err
		}
		ns += v * digit
		digit /= 10
	}
	// nanoseconds has 10-digits. (needs to scale digits)
	// 10 - 6 = 4, so we have to multiple 1000.
	return ns * 1000, nil
}

func bToi(b byte) (int, error) {
	if b < '0' || b > '9' {
		return 0, errors.New("not [0-9]")
	}
	return int(b - '0'), nil
}

func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
	switch num {
	case 0:
		return time.Time{}, nil
	case 4:
		return time.Date(
			int(binary.LittleEndian.Uint16(data[:2])), // year
			time.Month(data[2]),                       // month
			int(data[3]),                              // day
			0, 0, 0, 0,
			loc,
		), nil
	case 7:
		return time.Date(

View on GitHub (pinned to 03d76c7e07)