{"record":{"id":"b3cb9f340cb19f34","repo":"risingwavelabs/risingwave","slug":"failed-to-parse-mysql-timestamp-value","errorCode":null,"errorMessage":"failed to parse mysql timestamp value","messagePattern":"failed to parse mysql timestamp value","errorType":"exception","errorClass":"ConnectorError","httpStatus":null,"severity":"error","filePath":"src/connector/src/source/cdc/external/mysql.rs","lineNumber":264,"sourceCode":"            // interpret its value\n            if data_type == &DataType::Timestamptz {\n                val = timestamp_val_to_timestamptz(val.as_str())?;\n            }\n            Some(ScalarImpl::from_text(val.as_str(), data_type).map_err(|e| anyhow!(e)).context(\n                \"failed to parse mysql default value expression, only constant is supported\",\n            )?)\n        }\n        ColumnDefault::CurrentTimestamp | ColumnDefault::CustomExpr(_) => {\n            bail!(\"MySQL CURRENT_TIMESTAMP and custom expression default value not supported\")\n        }\n    };\n    Ok(datum)\n}\n\npub fn timestamp_val_to_timestamptz(value_text: &str) -> ConnectorResult<String> {\n    let format = \"%Y-%m-%d %H:%M:%S\";\n    let naive_datetime = NaiveDateTime::parse_from_str(value_text, format)\n        .map_err(|err| anyhow!(\"failed to parse mysql timestamp value\").context(err))?;\n    let postgres_timestamptz: DateTime<chrono::Utc> =\n        DateTime::<chrono::Utc>::from_naive_utc_and_offset(naive_datetime, chrono::Utc);\n    Ok(postgres_timestamptz\n        .format(\"%Y-%m-%d %H:%M:%S%:z\")\n        .to_string())\n}\n\npub fn type_name_to_mysql_type(ty_name: &str) -> Option<ColumnType> {\n    // Debezium schema change message may include extra qualifiers, e.g. `BIGINT UNSIGNED`,\n    // `BIGINT(20) UNSIGNED`, `INT UNSIGNED ZEROFILL`, etc.\n    let ty = ty_name.trim().to_lowercase();\n    let tokens = ty\n        .split(|c: char| c.is_whitespace() || matches!(c, '(' | ')' | ','))\n        .filter(|token| !token.is_empty())\n        .collect_vec();\n    let base = tokens.first().copied().unwrap_or_default();\n    let second = tokens.get(1).copied();\n    let is_unsigned = tokens.contains(&\"unsigned\");","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/source/cdc/external/mysql.rs#L246-L282","documentation":"timestamp_val_to_timestamptz parses a MySQL timestamp literal in the fixed format '%Y-%m-%d %H:%M:%S' and converts it to a UTC timestamptz string. If the text does not match this exact format, chrono's NaiveDateTime::parse_from_str fails and the error (with the chrono error as context) is returned.","triggerScenarios":"A MySQL TIMESTAMP/DATETIME column default whose string value includes fractional seconds ('2024-01-01 00:00:00.123'), timezone offsets, or another formatting variant; also reached via parse_schema_change handling default values.","commonSituations":"MySQL defaults like CURRENT_TIMESTAMP(3) resolved to values with microseconds; locale or zero-date values ('0000-00-00 00:00:00'); defaults written with 'T' separators.","solutions":["Normalize the MySQL default to 'YYYY-MM-DD HH:MM:SS' format (no fractional seconds, no 'T').","Replace the default with a constant literal in the accepted format.","Patch timestamp_val_to_timestamptz to accept fractional seconds (e.g. try multiple chrono formats) if you control the connector code."],"exampleFix":"// before (MySQL)\nALTER TABLE t MODIFY ts TIMESTAMP(3) DEFAULT '2024-01-01 00:00:00.000';\n// after\nALTER TABLE t MODIFY ts TIMESTAMP DEFAULT '2024-01-01 00:00:00';","handlingStrategy":"validation","validationCode":"function isMysqlTimestampLiteral(v) {\n  return /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(String(v));\n}","typeGuard":"function canParseAsNaiveDateTime(v) {\n  return /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(v) && !isNaN(Date.parse(v.replace(\" \", \"T\") + \"Z\"));\n}","tryCatchPattern":"try { await createCdcTable('t'); } catch (e) { if (String(e).includes('failed to parse mysql timestamp value')) { /* reformat the default to 'YYYY-MM-DD HH:MM:SS' in MySQL and retry */ } else throw e; }","preventionTips":["Format timestamp defaults as 'YYYY-MM-DD HH:MM:SS' with no fractional seconds or 'T'","Avoid TIMESTAMP(n) defaults that resolve to fractional-second literals","Never use zero-dates like '0000-00-00 00:00:00' as defaults"],"tags":["cdc","mysql","timestamp","parse"],"backgroundTag":"invalid-date-format","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}