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
- Inspect the actual bytes in the offending column (SELECT HEX(col)) to confirm corruption vs. misinterpretation.
- If the data is genuinely text, store/retrieve it as a string and parse with time.Parse yourself.
- Repair or reload the corrupted rows; validate at insert time to prevent recurrence.
- 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
- Validate datetime strings at insert time.
- Use SELECT HEX(col) to inspect suspect temporal data.
- Don't reinterpret text columns as DATE/DATETIME in the schema.
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
- bad value for field: `%c`
- invalid time bytes
- illegal length
- illegal packet length
- invalid compressed packet: uncompressed length in header is
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)