{"record":{"id":"90c6e55ad06c9cf2","repo":"go-sql-driver/mysql","slug":"bad-value-for-field-c","errorCode":null,"errorMessage":"bad value for field: `%c`","messagePattern":"bad value for field: `%c`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"utils.go","lineNumber":121,"sourceCode":"\n/******************************************************************************\n*                           Time related utils                                *\n******************************************************************************/\n\nfunc parseDateTime(b []byte, loc *time.Location) (time.Time, error) {\n\tconst base = \"0000-00-00 00:00:00.000000\"\n\tswitch len(b) {\n\tcase 10, 19, 21, 22, 23, 24, 25, 26: // up to \"YYYY-MM-DD HH:MM:SS.MMMMMM\"\n\t\tif string(b) == base[:len(b)] {\n\t\t\treturn time.Time{}, nil\n\t\t}\n\n\t\tyear, err := parseByteYear(b)\n\t\tif err != nil {\n\t\t\treturn time.Time{}, err\n\t\t}\n\t\tif b[4] != '-' {\n\t\t\treturn time.Time{}, fmt.Errorf(\"bad value for field: `%c`\", b[4])\n\t\t}\n\n\t\tm, err := parseByte2Digits(b[5], b[6])\n\t\tif err != nil {\n\t\t\treturn time.Time{}, err\n\t\t}\n\t\tmonth := time.Month(m)\n\n\t\tif b[7] != '-' {\n\t\t\treturn time.Time{}, fmt.Errorf(\"bad value for field: `%c`\", b[7])\n\t\t}\n\n\t\tday, err := parseByte2Digits(b[8], b[9])\n\t\tif err != nil {\n\t\t\treturn time.Time{}, err\n\t\t}\n\t\tif len(b) == 10 {\n\t\t\treturn time.Date(year, month, day, 0, 0, 0, 0, loc), nil","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/utils.go#L103-L139","documentation":"Raised by parseDateTime (utils.go:121) while decoding a TEXT-protocol DATE/DATETIME/TIMESTAMP value. After the 4-digit year is parsed, the byte at offset 4 must be '-' (the year/month separator in 'YYYY-MM-DD HH:MM:SS'). Any other byte means the value returned by the server is not a well-formed MySQL date string, so the driver refuses to coerce it into a Go time.Time.","triggerScenarios":"Scanning a DATE/DATETIME/TIMESTAMP column into a Go time.Time (requires DSN parseTime=true), or scanning into sql.NullTime, when the server's text value has a non '-' byte at position 4 — e.g. '2020/01/15 ...' (slash), '2020.01.15 ...' (dot), or truncated/corrupted rows. The path is rows.readRows -> parseDateTime (packets.go:875) or nulltime.Scan (nulltime.go:52).","commonSituations":"Applications that previously stored dates with locale-specific or slash separators, columns declared as VARCHAR/TEXT holding human-formatted dates but read as datetime, an sql_mode that allowed bad dates to be inserted, or data migrated from a non-MySQL source without normalization.","solutions":["Normalize the stored data so every date value matches 'YYYY-MM-DD[ HH:MM:SS[.ffffff]]' (e.g. UPDATE ... SET col = STR_TO_DATE(col, '%Y/%m/%d')).","If raw values must be preserved, scan into a string or []byte / sql.NullString instead of time.Time so parseDateTime is bypassed.","Switch the DSN to parseTime=false so the driver returns datetime columns as raw []byte, then parse defensively in your own code.","For non-DATE columns holding formatted dates, fix the schema/column type or the SELECT so the value arrives as a real DATE."],"exampleFix":"// before: assumes well-formed date\nvar t time.Time\nrows.Scan(&t)\n\n// after: tolerate non-standard separators by reading raw then parsing\nvar raw string\nif err := rows.Scan(&raw); err != nil { return err }\nt, err := time.Parse(\"2006/01/02 15:04:05\", raw)\nif err != nil { /* handle / skip row */ }","handlingStrategy":"validation","validationCode":"// Validate a text datetime value before relying on driver coercion.\nfunc isValidMySQLDateText(s string) bool {\n    if len(s) != 10 && !(len(s) >= 19 && len(s) <= 26) {\n        return false\n    }\n    if len(s) >= 5 && s[4] != '-' {\n        return false\n    }\n    _, err := time.Parse(\"2006-01-02\", s[:10])\n    return err == nil\n}","typeGuard":"func isCanonicalDateText(b []byte) bool {\n    return len(b) >= 10 && b[4] == '-' && b[7] == '-'\n}","tryCatchPattern":"// For parseTime=true scans, check the returned error.\nvar t time.Time\nif err := rows.Scan(&t); err != nil {\n    if strings.Contains(err.Error(), \"bad value for field\") {\n        // log/repair the offending row; rescan as string to inspect\n    }\n}","preventionTips":["Store dates only via parameterized time.Time or real DATE columns, never formatted strings.","Run SELECT ... WHERE col NOT REGEXP '^[0-9]{4}-[0-9]{2}-[0-9]{2}' to find malformed dates.","Keep parseTime=true only when your data is trusted canonical; otherwise scan into string.","Enforce sql_mode=STRICT_TRANS_TABLES to prevent invalid dates being inserted."],"tags":["mysql","datetime","parsing","text-protocol","parsetime"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}