apache/seatunnel · error · OptionValidationException
tables_configs[%d]: 'start_mode.offsets' is only valid when
Error message
tables_configs[%d]: 'start_mode.offsets' is only valid when start_mode=SPECIFIC_OFFSETS
What it means
In tables_configs, start_mode.offsets is only meaningful when start_mode=SPECIFIC_OFFSETS. evaluate() rejects entries that set start_mode=TIMESTAMP but also supply start_mode.offsets, since the two start strategies conflict.
Source
Thrown at seatunnel-connectors-v2/connector-kafka/src/main/java/org/apache/seatunnel/connectors/seatunnel/kafka/source/KafkaSourceFactory.java:215
@Override
public boolean evaluate(ReadonlyConfig config, List<Map<String, Object>> entries)
throws OptionValidationException {
if (entries == null || entries.isEmpty()) {
return true;
}
for (int i = 0; i < entries.size(); i++) {
ReadonlyConfig entryConfig = ReadonlyConfig.fromMap(entries.get(i));
StartMode startMode =
entryConfig.getOptional(KafkaSourceOptions.START_MODE).orElse(null);
if (startMode == StartMode.TIMESTAMP) {
Long ts = entryConfig.get(KafkaSourceOptions.START_MODE_TIMESTAMP);
if (ts == null || ts < 0) {
throw new OptionValidationException(
"tables_configs[%d]: 'start_mode.timestamp' must be >= 0, got: %d",
i, ts);
}
if (entries.get(i).containsKey(KafkaSourceOptions.START_MODE_OFFSETS.key())) {
throw new OptionValidationException(
"tables_configs[%d]: 'start_mode.offsets' is only valid "
+ "when start_mode=SPECIFIC_OFFSETS",
i);
}
Long endTs = entryConfig.get(KafkaSourceOptions.START_MODE_END_TIMESTAMP);
if (endTs != null && endTs < 0) {
throw new OptionValidationException(
"tables_configs[%d]: 'start_mode.end_timestamp' must be >= 0, got: %d",
i, endTs);
}
} else if (startMode == StartMode.SPECIFIC_OFFSETS) {
Map<String, Long> offsets =
entryConfig.get(KafkaSourceOptions.START_MODE_OFFSETS);
if (offsets == null || offsets.isEmpty()) {
throw new OptionValidationException(
"tables_configs[%d]: 'start_mode.offsets' must not be empty "
+ "when start_mode=SPECIFIC_OFFSETS",
i);View on GitHub (pinned to cf67b549a7)
Solutions
- Remove start_mode.offsets from entries where start_mode=TIMESTAMP.
- Change start_mode to SPECIFIC_OFFSETS if you actually want explicit offsets.
- Audit each tables_configs entry for mutually exclusive options before submission.
Example fix
// before
start_mode = TIMESTAMP
start_mode.timestamp = 1704067200000
start_mode.offsets = {partition-0: 100}
// after
start_mode = TIMESTAMP
start_mode.timestamp = 1704067200000 Defensive patterns
Strategy: validation
Validate before calling
if (!"SPECIFIC_OFFSETS".equals(entry.get("start_mode")) && entry.containsKey("start_mode.offsets")) { throw new IllegalArgumentException("start_mode.offsets requires start_mode=SPECIFIC_OFFSETS"); } Try / catch
try { factory.evaluate(ctx); } catch (OptionValidationException e) { stripConflictingOptions(ctx); reevaluate(ctx); } Prevention
- Keep per-mode option sets disjoint when generating table configs.
- Clean stale keys when switching start modes.
When it happens
Trigger: A tables_configs entry combining start_mode=TIMESTAMP with a start_mode.offsets map present (even empty); detected in KafkaSourceFactory.evaluate at job build time.
Common situations: Merging/reusing per-table config blocks that accumulate stale options; template configs carrying offsets plus a later-switched timestamp mode.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- tables_configs[%d]: 'start_mode.timestamp' is only valid whe
- start_mode.timestamp must not be greater than the current ti
- start_mode.end_timestamp must not be greater than the curren
- tables_configs[%d]: 'start_mode.timestamp' must be >= 0, got
- tables_configs[%d]: 'start_mode.end_timestamp' must be >= 0,
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/7acaca4c489ac545.
Report an issue: GitHub.