prestodb/presto · error · IllegalArgumentException
Invalid Kafka Offset start/end pair: %s - %s
Error message
Invalid Kafka Offset start/end pair: %s - %s
What it means
getSplits validates the timestamp bounds from the KafkaTableLayoutHandle: if startTimestamp > endTimestamp it throws an IllegalArgumentException 'Invalid Kafka Offset start/end pair'. These timestamps translate to offsets via offsetsForTimes, so an inverted range is a caller/config error, not a Kafka failure.
Source
Thrown at presto-kafka/src/main/java/com/facebook/presto/kafka/KafkaSplitManager.java:109
KafkaTableLayoutHandle layoutHandle = (KafkaTableLayoutHandle) layout;
HostAddress node = KafkaClusterMetadataHelper.selectRandom(clusterMetadataSupplier.getNodes(layoutHandle.getTable().getSchemaName()));
KafkaConsumer<ByteBuffer, ByteBuffer> consumer = consumerManager.createConsumer(Thread.currentThread().getName(), node);
List<PartitionInfo> partitions = consumer.partitionsFor(topic);
ImmutableList.Builder<ConnectorSplit> splits = ImmutableList.builder();
for (PartitionInfo partition : partitions) {
Node leader = partition.leader();
if (leader == null) {
throw new PrestoException(GENERIC_INTERNAL_ERROR, format("Leader election in progress for Kafka topic '%s' partition %s", topic, partition.partition()));
}
HostAddress partitionLeader = HostAddress.fromParts(leader.host(), leader.port());
long startTimestamp = layoutHandle.getStartOffsetTimestamp();
long endTimestamp = layoutHandle.getEndOffsetTimestamp();
if (startTimestamp > endTimestamp) {
throw new IllegalArgumentException(String.format("Invalid Kafka Offset start/end pair: %s - %s", startTimestamp, endTimestamp));
}
TopicPartition topicPartition = new TopicPartition(partition.topic(), partition.partition());
consumer.assign(ImmutableList.of(topicPartition));
long beginningOffset = (startTimestamp == 0) ?
consumer.beginningOffsets(ImmutableList.of(topicPartition)).values().iterator().next() :
findOffsetsByTimestamp(consumer, topicPartition, startTimestamp);
long endOffset = (endTimestamp == 0) ?
consumer.endOffsets(ImmutableList.of(topicPartition)).values().iterator().next() :
findOffsetsByTimestamp(consumer, topicPartition, endTimestamp);
KafkaSplit split = new KafkaSplit(
connectorId,
topic,
kafkaTableHandle.getKeyDataFormat(),
kafkaTableHandle.getMessageDataFormat(),
kafkaTableHandle.getKeyDataSchemaLocation().map(KafkaSplitManager::readSchema),View on GitHub (pinned to 55bb57d202)
Solutions
- Fix the table's start-offset-timestamp/end-offset-timestamp properties so start <= end
- Correct the ordering of the values supplied by the calling tool/job
- Drop and recreate the table description with valid timestamp bounds
Example fix
// before "startOffsetTimestamp": 1700000000000, "endOffsetTimestamp": 1600000000000 // after "startOffsetTimestamp": 1600000000000, "endOffsetTimestamp": 1700000000000
Defensive patterns
Strategy: validation
Validate before calling
if (startOffsetTimestamp > endOffsetTimestamp)
throw new IllegalArgumentException("start must be <= end"); Type guard
null
Try / catch
null
Prevention
- Validate start/end timestamp ordering in table DDL tooling
- Use named constants/variables to avoid swapping arguments
- Document that timestamps are epoch milliseconds
When it happens
Trigger: A Kafka table layout was created with start-offset-timestamp greater than end-offset-timestamp (e.g. via a table property or session-level time-range constraint) and then getSplits runs a query on that table.
Common situations: Swapped start/end values in CREATE TABLE properties; a UI or scheduler passing (end, start) in the wrong order; timezone/unit confusion producing end < start.
Related errors
- KAFKA_CONSUMER_ERROR
- Invalid value [%s]. Valid values: %s
- INVALID_SESSION_PROPERTY
- iceberg.target-max-file-size must be at least 1 byte
- INVALID_SESSION_PROPERTY
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/1e546ee4fd7b895d.
Report an issue: GitHub.