go-sql-driver/mysql · error

illegal %s length %d

Error message

illegal %s length %d

What it means

Thrown by formatBinaryDateTime (utils.go:404) when the DECLARED column length `length` is not in {10, 19, 21, 22, 23, 24, 25, 26} — the only legal text lengths for DATE (10) or DATETIME (19, or 19+fraction). The function builds the text representation of a binary DATE/DATETIME value and rejects lengths it cannot format. The interpolated type is 'DATE' or 'DATETIME'.

Source

Thrown at utils.go:404

}

func formatBinaryDateTime(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[:length], nil
	}
	var dst []byte      // return value
	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],

View on GitHub (pinned to c426bd9379)

Solutions

  1. Reproduce with the text protocol (plain db.Query without placeholders, or CAST(col AS CHAR)) to isolate binary-protocol corruption.
  2. Bypass proxies/routers; connect directly to MySQL and confirm the column type/length with SHOW COLUMNS.
  3. Check the server is a genuine MySQL/MariaDB and is on a supported version.
  4. Report with the exact length value from the message if it reproduces against vanilla MySQL.

Example fix

// before
rows, _ := db.Query("SELECT d FROM t WHERE id=?", id)

// after: read as text for diagnosis
var s string
db.QueryRow("SELECT CAST(d AS CHAR) FROM t WHERE id=?", id).Scan(&s)
Defensive patterns

Strategy: try-catch

Try / catch

if err := rows.Scan(...); err != nil {
    if strings.Contains(err.Error(), "illegal ") && strings.Contains(err.Error(), "length") {
        // declared column length is unsupported; read via CAST AS CHAR
    }
}

Prevention

When it happens

Trigger: Result scanning a DATE/DATETIME column from a binary-protocol row where the column metadata's declared length is unexpected — e.g. a malformed binary result set, or a server/column definition with a non-standard length. Fires from Scan on prepared-statement rows.

Common situations: Corrupted binary row packets (flaky network, buggy proxy); a non-MySQL server advertising odd column lengths; version skew between client expectations and server; buffer corruption. Rare under normal operation.

Related errors


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