go-sql-driver/mysql · error

illegal %s packet length %d

Error message

illegal %s packet length %d

What it means

Thrown by formatBinaryDateTime (utils.go:413) when the ACTUAL payload byte length `len(src)` is not one of {4, 7, 11} — the only valid binary DATE/DATETIME payload sizes (date / date+time / date+time+micros). Distinct from error 47 which checks the declared column length; this checks the real bytes received.

Source

Thrown at utils.go:413

	var p1, p2, p3 byte // current digit pair

	switch length {
	case 10, 19, 21, 22, 23, 24, 25, 26:
	default:
		t := "DATE"
		if length > 10 {
			t += "TIME"
		}
		return nil, fmt.Errorf("illegal %s length %d", t, length)
	}
	switch len(src) {
	case 4, 7, 11:
	default:
		t := "DATE"
		if length > 10 {
			t += "TIME"
		}
		return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
	}
	dst = make([]byte, 0, length)
	// start with the date
	year := binary.LittleEndian.Uint16(src[:2])
	pt := year / 100
	p1 = byte(year - 100*uint16(pt))
	p2, p3 = src[2], src[3]
	dst = append(dst,
		digits10[pt], digits01[pt],
		digits10[p1], digits01[p1], '-',
		digits10[p2], digits01[p2], '-',
		digits10[p3], digits01[p3],
	)
	if length == 10 {
		return dst, nil
	}
	if len(src) == 4 {
		return append(dst, zeroDateTime[10:length]...), nil

View on GitHub (pinned to c426bd9379)

Solutions

  1. Note the actual length in the message and reproduce with the text protocol (CAST AS CHAR) to confirm whether the binary path is the culprit.
  2. Eliminate proxies/tunnels; connect directly to MySQL and retry the prepared statement.
  3. Verify server version and column type with SHOW COLUMNS.
  4. If it reproduces against vanilla MySQL, report upstream with the length value and column DDL.

Example fix

// before
var t time.Time
db.QueryRow("SELECT d FROM t WHERE id=?", id).Scan(&t)

// after
var raw string
if err := db.QueryRow("SELECT CAST(d AS CHAR) FROM t WHERE id=?", id).Scan(&raw); err == nil {
    t, err = time.ParseInLocation("2006-01-02 15:04:05", raw, time.Local)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := rows.Scan(...); err != nil {
    if strings.Contains(err.Error(), "illegal ") && strings.Contains(err.Error(), "packet length") {
        // actual binary payload size is wrong; fall back to text protocol
    }
}

Prevention

When it happens

Trigger: Reading a DATE/DATETIME column via the binary protocol where the actual bytes in the row packet don't match a valid payload size — truncated packets, padding corruption, or a non-conforming server. Fires during Scan on prepared-statement rows.

Common situations: Truncated/corrupted binary row packets over a flaky link; a proxy/router that mishandles binary datetime payloads; server-version mismatch; rare memory corruption. The message reports the actual (invalid) byte count.

Related errors


AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04). Data as JSON: /data/errors/7e1f26b5f1a33d2a.json. Report an issue: GitHub.