{"record":{"id":"17ec3353208d0ef6","repo":"go-sql-driver/mysql","slug":"illegal-s-length-d","errorCode":null,"errorMessage":"illegal %s length %d","messagePattern":"illegal (.+?) length (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"utils.go","lineNumber":404,"sourceCode":"}\n\nfunc formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) {\n\t// length expects the deterministic length of the zero value,\n\t// negative time and 100+ hours are automatically added if needed\n\tif len(src) == 0 {\n\t\treturn zeroDateTime[:length], nil\n\t}\n\tvar dst []byte      // return value\n\tvar p1, p2, p3 byte // current digit pair\n\n\tswitch length {\n\tcase 10, 19, 21, 22, 23, 24, 25, 26:\n\tdefault:\n\t\tt := \"DATE\"\n\t\tif length > 10 {\n\t\t\tt += \"TIME\"\n\t\t}\n\t\treturn nil, fmt.Errorf(\"illegal %s length %d\", t, length)\n\t}\n\tswitch len(src) {\n\tcase 4, 7, 11:\n\tdefault:\n\t\tt := \"DATE\"\n\t\tif length > 10 {\n\t\t\tt += \"TIME\"\n\t\t}\n\t\treturn nil, fmt.Errorf(\"illegal %s packet length %d\", t, len(src))\n\t}\n\tdst = make([]byte, 0, length)\n\t// start with the date\n\tyear := binary.LittleEndian.Uint16(src[:2])\n\tpt := year / 100\n\tp1 = byte(year - 100*uint16(pt))\n\tp2, p3 = src[2], src[3]\n\tdst = append(dst,\n\t\tdigits10[pt], digits01[pt],","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/utils.go#L386-L422","documentation":"Raised by formatBinaryDateTime (utils.go:404) for the DISPLAY length. After receiving a binary DATE/DATETIME, the driver computes a target display length from the column's decimals metadata; if that length is not in {10, 19, 21-26} the driver refuses to format it (type becomes 'DATE' or 'DATETIME'). Because the preceding decimals switch in packets.go already rejects invalid decimals, reaching this line means the column metadata itself reported an inconsistent length/decimals combination — effectively a protocol-level integrity violation.","triggerScenarios":"Reading a DATE/DATETIME/TIMESTAMP column from a prepared-statement result set (parseTime=false, so the driver formats the binary value to text) where the column metadata advertises a length outside the canonical set. Reached via formatBinaryDateTime at packets.go:1434. Realistically only with a non-conforming server/proxy or after packet desync, since the driver pre-validates decimals.","commonSituations":"Buggy MySQL-compatible server or middleware returning malformed column definitions, result-set schema drift after an ALTER that the proxy cached incorrectly, packet corruption, or a server speaking a non-standard temporal encoding.","solutions":["Identify and patch/upgrade the server or proxy returning the bad column metadata (capture via SHOW WARNINGS / EXPLAIN / general log).","For that column, scan raw bytes instead of relying on driver formatting (read into []byte and parse yourself).","Re-run the query without prepared statements to use the text protocol, which bypasses formatBinaryDateTime entirely.","Reconnect/re-prepare to refresh cached metadata if the schema was altered."],"exampleFix":"// before: relies on driver binary->text formatting\ndb.QueryRow(`SELECT ts FROM t WHERE id=?`, id).Scan(&s)\n\n// after: read raw and parse, or switch to text protocol\nvar raw []byte\ndb.QueryRow(`SELECT CAST(ts AS CHAR) FROM t WHERE id=?`, id).Scan(&raw)","handlingStrategy":"try-catch","validationCode":"// Column metadata is server-controlled; validate by reading the column's\n// length/decimals via INFORMATION_SCHEMA before relying on binary formatting.\nfunc validDateDisplayLen(l uint8) bool {\n    switch l {\n    case 10, 19, 21, 22, 23, 24, 25, 26:\n        return true\n    }\n    return false\n}","typeGuard":"func isCanonicalDateDisplayLen(l uint8) bool {\n    switch l {\n    case 10, 19, 21, 22, 23, 24, 25, 26:\n        return true\n    }\n    return false\n}","tryCatchPattern":"var s string\nif err := db.QueryRow(q, id).Scan(&s); err != nil {\n    if strings.Contains(err.Error(), \"illegal\") && strings.Contains(err.Error(), \"length\") {\n        var raw []byte\n        _ = db.QueryRow(`SELECT CAST(col AS CHAR) FROM t WHERE id=?`, id).Scan(&raw)\n        s = string(raw)\n    }\n}","preventionTips":["Use CAST(... AS CHAR) for temporal columns served by proxies of uncertain compliance.","Avoid prepared statements for DATETIME columns through flaky middleware.","Re-prepare statements after schema changes to refresh metadata."],"tags":["mysql","datetime","binary-protocol","prepared-statements","protocol-error"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}