{"record":{"id":"16d3f5c15a746c80","repo":"go-sql-driver/mysql","slug":"illegal-time-length-d","errorCode":null,"errorMessage":"illegal TIME length %d","messagePattern":"illegal TIME length (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"utils.go","lineNumber":460,"sourceCode":"\t\tdigits10[p3], digits01[p3],\n\t)\n\treturn appendMicrosecs(dst, src[2:], int(length)-20), nil\n}\n\nfunc formatBinaryTime(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[11 : 11+length], nil\n\t}\n\tvar dst []byte // return value\n\n\tswitch length {\n\tcase\n\t\t8,                      // time (can be up to 10 when negative and 100+ hours)\n\t\t10, 11, 12, 13, 14, 15: // time with fractional seconds\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"illegal TIME length %d\", length)\n\t}\n\tswitch len(src) {\n\tcase 8, 12:\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid TIME packet length %d\", len(src))\n\t}\n\t// +2 to enable negative time and 100+ hours\n\tdst = make([]byte, 0, length+2)\n\tif src[0] == 1 {\n\t\tdst = append(dst, '-')\n\t}\n\tdays := binary.LittleEndian.Uint32(src[1:5])\n\thours := int64(days)*24 + int64(src[5])\n\n\tif hours >= 100 {\n\t\tdst = strconv.AppendInt(dst, hours, 10)\n\t} else {\n\t\tdst = append(dst, digits10[hours], digits01[hours])","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/utils.go#L442-L478","documentation":"Raised by formatBinaryTime (utils.go:460) for the DISPLAY length. The driver computes a target display length for a binary TIME value from the column's decimals; valid lengths are {8 (no fractional), 10-15 (with 1-6 fractional digits)}. An out-of-range length means the column metadata is internally inconsistent. Because packets.go pre-validates decimals, reaching this line implies protocol corruption rather than a normal data value.","triggerScenarios":"Reading a TIME column from a prepared-statement result set (parseTime=false) when the column metadata yields a display length outside {8, 10-15}. Reached via formatBinaryTime at packets.go:1414. Practically limited to non-conforming MySQL-compatible servers, stale cached metadata after schema changes, or packet desync.","commonSituations":"A proxy/sharder returning malformed TIME column definitions, schema drift after ALTER TIME column, or an exotic server encoding TIME differently than the standard binary protocol.","solutions":["Patch/upgrade the server or proxy returning invalid TIME metadata; verify with a direct mysql client.","Read the TIME column raw ([]byte) or CAST(... AS CHAR) in SQL to bypass binary formatting.","Run the query without prepared statements to use the text protocol.","Re-prepare / reconnect to refresh column metadata."],"exampleFix":"// before: driver formats binary TIME\ndb.QueryRow(`SELECT duration FROM t WHERE id=?`, id).Scan(&dur)\n\n// after: let the server convert to text\nvar dur string\ndb.QueryRow(`SELECT CAST(duration AS CHAR) FROM t WHERE id=?`, id).Scan(&dur)","handlingStrategy":"try-catch","validationCode":"func validTimeDisplayLen(l uint8) bool {\n    switch l {\n    case 8, 10, 11, 12, 13, 14, 15:\n        return true\n    }\n    return false\n}","typeGuard":"func isCanonicalTimeDisplayLen(l uint8) bool {\n    switch l {\n    case 8, 10, 11, 12, 13, 14, 15:\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 TIME length\") {\n        var raw []byte\n        _ = db.QueryRow(`SELECT CAST(dur AS CHAR) FROM t WHERE id=?`, id).Scan(&raw)\n        s = string(raw)\n    }\n}","preventionTips":["Cast TIME columns to CHAR when reading through proxies of unknown compliance.","Avoid prepared statements for TIME columns through flaky middleware.","Reconnect to refresh column metadata after ALTER TABLE on TIME columns."],"tags":["mysql","time","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"}