go-sql-driver/mysql · error
illegal TIME length %d
Error message
illegal TIME length %d
What it means
Thrown by formatBinaryTime (utils.go:460) when the DECLARED length of a binary TIME column is not in {8, 10, 11, 12, 13, 14, 15} — the legal binary TIME lengths (8 bytes base, plus fractional-second bytes). MySQL TIME can be negative or exceed 24h, and the driver only knows how to render these specific declared lengths.
Source
Thrown at utils.go:460
digits10[p3], digits01[p3],
)
return appendMicrosecs(dst, src[2:], int(length)-20), nil
}
func formatBinaryTime(src []byte, length uint8) (driver.Value, error) {
// length expects the deterministic length of the zero value,
// negative time and 100+ hours are automatically added if needed
if len(src) == 0 {
return zeroDateTime[11 : 11+length], nil
}
var dst []byte // return value
switch length {
case
8, // time (can be up to 10 when negative and 100+ hours)
10, 11, 12, 13, 14, 15: // time with fractional seconds
default:
return nil, fmt.Errorf("illegal TIME length %d", length)
}
switch len(src) {
case 8, 12:
default:
return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
}
// +2 to enable negative time and 100+ hours
dst = make([]byte, 0, length+2)
if src[0] == 1 {
dst = append(dst, '-')
}
days := binary.LittleEndian.Uint32(src[1:5])
hours := int64(days)*24 + int64(src[5])
if hours >= 100 {
dst = strconv.AppendInt(dst, hours, 10)
} else {
dst = append(dst, digits10[hours], digits01[hours])View on GitHub (pinned to c426bd9379)
Solutions
- Inspect the column with SHOW COLUMNS / DESCRIBE and confirm it is a TIME type with a sane fractional precision.
- Reproduce against the text protocol (CAST(col AS CHAR) or plain Query without ?) to isolate binary-path corruption.
- Bypass proxies/tunnels and connect directly to MySQL.
- If reproducible on vanilla MySQL, report upstream with the length value and column DDL.
Example fix
// before
var d time.Duration
db.QueryRow("SELECT elapsed FROM t WHERE id=?", id).Scan(&d)
// after
var raw string
if err := db.QueryRow("SELECT CAST(elapsed AS CHAR) FROM t WHERE id=?", id).Scan(&raw); err == nil {
// parse 'HH:MM:SS' or '-HH:MM:SS' into a duration manually
} Defensive patterns
Strategy: try-catch
Try / catch
if err := rows.Scan(...); err != nil {
if strings.Contains(err.Error(), "illegal TIME length") {
// declared TIME length unsupported; read via CAST AS CHAR
}
} Prevention
- Confirm TIME columns have a standard fractional precision via SHOW COLUMNS.
- Bypass proxies/routers that rewrite binary column metadata.
- Reproduce against a direct MySQL connection before assuming driver/server bugs.
When it happens
Trigger: Scanning a MySQL TIME column from a binary-protocol row whose column metadata declares an unsupported length — corrupted column definition, non-MySQL server, or packet mangling. Fires during Scan on prepared-statement rows that touch a TIME column.
Common situations: A buggy proxy/router rewriting binary result metadata; a non-conforming MySQL fork; version skew; rare buffer corruption. The message reports the offending declared length.
Related errors
- invalid TIME packet length %d
- invalid DATETIME packet length %d
- illegal %s length %d
- illegal %s packet length %d
- protocol error, illegal decimals value %d
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/16d3f5c15a746c80.json.
Report an issue: GitHub.