go-sql-driver/mysql · error

invalid TIME packet length %d

Error message

invalid TIME packet length %d

What it means

Thrown by formatBinaryTime (utils.go:465) when the ACTUAL payload byte length of a binary TIME value is not in {8, 12} — the only valid binary TIME payload sizes (8 bytes without fraction, 12 with micros). Distinct from error 49 which checks the declared length; this checks the bytes actually received.

Source

Thrown at utils.go:465

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])
	}

	min, sec := src[6], src[7]
	dst = append(dst, ':',
		digits10[min], digits01[min], ':',

View on GitHub (pinned to c426bd9379)

Solutions

  1. Note the actual length in the message; reproduce with the text protocol (CAST AS CHAR or plain Query) to confirm the binary path is at fault.
  2. Connect directly to MySQL, bypassing any proxy/router/tunnel.
  3. Verify the column type and server version with SHOW COLUMNS and SELECT VERSION().
  4. Report upstream if it reproduces against vanilla MySQL, including the length and column DDL.

Example fix

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

// after: read text for diagnosis
var raw string
if err := db.QueryRow("SELECT TIME_FORMAT(elapsed, '%H:%i:%s') FROM t WHERE id=?", id).Scan(&raw); err == nil {
    // parse manually
}
Defensive patterns

Strategy: try-catch

Try / catch

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

Prevention

When it happens

Trigger: Reading a TIME column via the binary protocol where the row packet's TIME payload has a byte count other than 8 or 12 — truncated packet, padding corruption, non-conforming server. Fires during Scan on prepared-statement rows touching a TIME column.

Common situations: Truncated/corrupted binary row data over a flaky network; a proxy/router mishandling binary TIME payloads; server-version mismatch; rare memory corruption. The message reports the actual invalid length.

Related errors


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