go-sql-driver/mysql · error
invalid DATETIME packet length %d
Error message
invalid DATETIME packet length %d
What it means
Thrown by parseBinaryDateTime (utils.go:265) — the fallback of its switch — when decoding a BINARY-protocol DATETIME value whose declared length `num` is not one of {0, 4, 7, 11}. MySQL's binary protocol only sends DATETIME payloads of those exact lengths (date / date+time / date+time+fraction), so any other length is a protocol violation.
Source
Thrown at utils.go:265
int(data[4]), // hour
int(data[5]), // minutes
int(data[6]), // seconds
0,
loc,
), nil
case 11:
return time.Date(
int(binary.LittleEndian.Uint16(data[:2])), // year
time.Month(data[2]), // month
int(data[3]), // day
int(data[4]), // hour
int(data[5]), // minutes
int(data[6]), // seconds
int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds
loc,
), nil
}
return nil, fmt.Errorf("invalid DATETIME packet length %d", num)
}
func appendDateTime(buf []byte, t time.Time, timeTruncate time.Duration) ([]byte, error) {
if timeTruncate > 0 {
t = t.Truncate(timeTruncate)
}
year, month, day := t.Date()
hour, min, sec := t.Clock()
nsec := t.Nanosecond()
if year < 1 || year > 9999 {
return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap
}
year100 := year / 100
year1 := year % 100
var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escapeView on GitHub (pinned to c426bd9379)
Solutions
- Run the same prepared-statement query in the mysql CLI (or with a plain db.Query without ? to force the text protocol) and see if it succeeds.
- Inspect the network path for proxies/routers that may mangle binary row data; connect directly to MySQL.
- Confirm server version and that the column is a real DATETIME/TIMESTAMP.
- If reproducible only via a specific proxy, file a bug with the proxy vendor; meanwhile disable compression and proxies.
Example fix
// before: binary protocol via prepared statement
rows, err := db.Query("SELECT created_at FROM orders WHERE id = ?", id)
// after: force text protocol to bypass the bad binary path for diagnosis
rows, err := db.Query("SELECT created_at FROM orders WHERE id = " + strconv.Itoa(id)) Defensive patterns
Strategy: try-catch
Try / catch
var t time.Time
if err := rows.Scan(&t); err != nil {
if strings.Contains(err.Error(), "invalid DATETIME packet length") {
// binary-protocol corruption; retry once, or fall back to text protocol
}
} Prevention
- Use the text protocol (plain db.Query without ?) for environments with flaky binary-row paths.
- Eliminate proxies/routers that mangle binary datetime payloads.
- Keep server and driver versions on supported, compatible releases.
When it happens
Trigger: Reading a DATETIME/TIMESTAMP column over the binary (prepared-statement) protocol where the server advertises an unsupported payload length — e.g. a corrupted or truncated binary row packet, or a non-conforming server/proxy. Fires during Scan on rows from a prepared statement (db.Query with ? placeholders uses the binary protocol).
Common situations: Packet corruption from a flaky network or a misbehaving proxy/router between app and MySQL; an exotic MySQL fork that emits non-standard binary datetime lengths; an old/new server version mismatch; memory/packet buffer corruption.
Related errors
- illegal %s length %d
- illegal %s packet length %d
- illegal TIME length %d
- invalid TIME packet length %d
- invalid time bytes: %s
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/1b8230956a1bdafa.json.
Report an issue: GitHub.