{"record":{"id":"0ff0ece2fce1ed17","repo":"apache/seatunnel","slug":"tables-configs-d-start-mode-timestamp-require","errorCode":null,"errorMessage":"tables_configs[%d]: 'start.mode.timestamp' required when start.mode=CONSUME_FROM_TIMESTAMP","messagePattern":"tables_configs\\[(.+?)\\]: 'start\\.mode\\.timestamp' required when start\\.mode=CONSUME_FROM_TIMESTAMP","errorType":"error_code","errorClass":"OptionValidationException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-rocketmq/src/main/java/org/apache/seatunnel/connectors/seatunnel/rocketmq/source/RocketMqSourceFactory.java","lineNumber":143,"sourceCode":"            if (entries == null || entries.isEmpty()) {\n                return true;\n            }\n            for (int i = 0; i < entries.size(); i++) {\n                ReadonlyConfig tableConfig = ReadonlyConfig.fromMap(entries.get(i));\n                String topics = tableConfig.get(RocketMqSourceOptions.TOPICS);\n                if (topics == null || topics.trim().isEmpty()) {\n                    throw new OptionValidationException(\n                            \"tables_configs[%d]: 'topics' must not be empty\", i);\n                }\n                StartMode startMode =\n                        tableConfig.getOptional(RocketMqSourceOptions.START_MODE).orElse(null);\n                if (startMode == StartMode.CONSUME_FROM_TIMESTAMP) {\n                    Long ts =\n                            tableConfig\n                                    .getOptional(RocketMqSourceOptions.START_MODE_TIMESTAMP)\n                                    .orElse(null);\n                    if (ts == null) {\n                        throw new OptionValidationException(\n                                \"tables_configs[%d]: 'start.mode.timestamp' required \"\n                                        + \"when start.mode=CONSUME_FROM_TIMESTAMP\",\n                                i);\n                    }\n                    if (ts < 0) {\n                        throw new OptionValidationException(\n                                \"tables_configs[%d]: 'start.mode.timestamp' must be >= 0, got: %d\",\n                                i, ts);\n                    }\n                } else if (startMode == StartMode.CONSUME_FROM_SPECIFIC_OFFSETS) {\n                    Map<String, Long> offsets =\n                            tableConfig\n                                    .getOptional(RocketMqSourceOptions.START_MODE_OFFSETS)\n                                    .orElse(null);\n                    if (offsets == null || offsets.isEmpty()) {\n                        throw new OptionValidationException(\n                                \"tables_configs[%d]: 'start.mode.offsets' must not be empty \"\n                                        + \"when start.mode=CONSUME_FROM_SPECIFIC_OFFSETS\",","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-rocketmq/src/main/java/org/apache/seatunnel/connectors/seatunnel/rocketmq/source/RocketMqSourceFactory.java#L125-L161","documentation":"When a tables_configs entry sets start.mode = CONSUME_FROM_TIMESTAMP, the connector requires `start.mode.timestamp` to be present. evaluate() throws OptionValidationException if the timestamp option is missing. Without it the connector cannot compute the consume-from point.","triggerScenarios":"Setting `start.mode = \"CONSUME_FROM_TIMESTAMP\"` in a table entry while omitting `start.mode.timestamp`; detected in RocketMqSourceFactory.evaluate during config validation.","commonSituations":"Copying a config that used a different start mode, renaming the timestamp key incorrectly, or assuming the timestamp defaults to 'now' — it does not.","solutions":["Add `start.mode.timestamp` (epoch milliseconds) to the table entry that uses CONSUME_FROM_TIMESTAMP","Or change start.mode to a mode that needs no timestamp (e.g. CONSUME_FROM_LATEST, EARLIEST)","Confirm the option key spelling matches RocketMqSourceOptions.START_MODE_TIMESTAMP (start.mode.timestamp)"],"exampleFix":"// before\nstart.mode = \"CONSUME_FROM_TIMESTAMP\"\n// after\nstart.mode = \"CONSUME_FROM_TIMESTAMP\"\nstart.mode.timestamp = 1700000000000","handlingStrategy":"validation","validationCode":"if (\"CONSUME_FROM_TIMESTAMP\".equals(cfg.get(\"start.mode\")) && cfg.get(\"start.mode.timestamp\") == null)\n    throw new IllegalArgumentException(\"start.mode.timestamp required for CONSUME_FROM_TIMESTAMP\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set timestamp together with the start mode in your config generator","Use a lint script that cross-checks start.mode against its companion options","Document the required pair in your team's config snippets"],"tags":["config","validation","rocketmq"],"backgroundTag":"missing-required-config-field","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}