go-sql-driver/mysql · error

protocol error, illegal decimals value %d

Error message

protocol error, illegal decimals value %d

What it means

A protocol-level error while decoding a binary-protocol TIME column from a prepared-statement result row (packets.go:1409): the column's decimals metadata byte is not 0x00, 0x1f, or 1-6, the only legal values per the MySQL binary protocol. The driver's adjacent comment urges reporting it, signaling it should not occur with a conformant server. It indicates a malformed or non-conforming server/proxy response.

Source

Thrown at packets.go:1409

			fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal]

			num, isNull, n := readLengthEncodedInteger(data[pos:])
			pos += n

			switch {
			case isNull:
				dest[i] = nil
				continue
			case rows.rs.columns[i].fieldType == fieldTypeTime:
				// database/sql does not support an equivalent to TIME, return a string
				var dstlen uint8
				switch decimals := rows.rs.columns[i].decimals; decimals {
				case 0x00, 0x1f:
					dstlen = 8
				case 1, 2, 3, 4, 5, 6:
					dstlen = 8 + 1 + decimals
				default:
					return fmt.Errorf(
						"protocol error, illegal decimals value %d",
						rows.rs.columns[i].decimals,
					)
				}
				dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen)
			case rows.mc.parseTime:
				dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
			default:
				var dstlen uint8
				if rows.rs.columns[i].fieldType == fieldTypeDate {
					dstlen = 10
				} else {
					switch decimals := rows.rs.columns[i].decimals; decimals {
					case 0x00, 0x1f:
						dstlen = 19
					case 1, 2, 3, 4, 5, 6:
						dstlen = 19 + 1 + decimals
					default:

View on GitHub (pinned to c426bd9379)

Solutions

  1. Reproduce against a vanilla MySQL/MariaDB server to confirm it is a server/proxy bug.
  2. Upgrade or patch the offending server or proxy that generates the result set.
  3. Work around it by casting the column in SQL, e.g. SELECT CAST(t AS CHAR) AS t.
  4. Report the bug to the driver maintainers with the server/proxy version details.

Example fix

// before
rows, _ := db.Query("SELECT t FROM events")  // t is TIME with malformed metadata

// after — force a string to bypass binary TIME decoding
rows, _ := db.Query("SELECT CAST(t AS CHAR) AS t FROM events")
Defensive patterns

Strategy: fallback

Try / catch

if err := rows.Scan(dest...); err != nil {
    if strings.Contains(err.Error(), "illegal decimals value") && strings.Contains(err.Error(), "protocol error") {
        // server/proxy sent malformed TIME metadata; re-issue with CAST(t AS CHAR)
    }
}

Prevention

When it happens

Trigger: Reading rows from a prepared statement over a connection to a buggy/non-conforming server or middleware (ProxySQL, Vitess, a custom sharding layer) that emits an invalid decimals byte for a TIME column; packet corruption in transit.

Common situations: A proxy generating malformed column definitions; an extremely old or patched server; rare genuine driver/server version skew.

Related errors


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