provectus/kafka-ui · error · ValidationException
Topic partition has no leader
Error message
Topic partition %s has no leader
What it means
ReactiveAdminClient.filterPartitionsWithLeaderCheck inspects TopicDescription metadata and throws ValidationException when a partition has no leader broker. Without a leader, offset lookups cannot be served for that partition, so operations like listOffsets would fail; when failOnUnknownLeader is true the client fails fast instead of returning incomplete data. When false, partitions of that topic are silently skipped rather than throwing.
Solutions
- Restore broker availability: restart/recover the down broker(s) so a leader is elected for the affected partitions.
- Increase the topic's replication factor (>= 2) so leader election can occur when one replica is down.
- Retry the offset listing after the controller finishes leader election (the condition is usually transient).
- Check `kafka-topics --describe --under-replicated-partitions` / `--unavailable-partitions` and fix the offline partitions.
- If using the code path directly, set failOnUnknownLeader=false to skip leaderless topics instead of throwing.
Example fix
// before: fail immediately on leaderless partitions
ListOffsetsResult result = adminClient.listOffsets(offsetsToFetch);
// after: tolerate/skip leaderless partitions
// (in listOffsets call chain) use failOnUnknownLeader=false so
// filterPartitionsWithLeaderCheck skips topics with leaderless partitions
Map<TopicPartition, OffsetSpec> fetchable = filterPartitionsWithLeaderCheck(
adminClient.describeTopics(names).allTopicNames().get(), fetch, false); Defensive patterns
Strategy: retry
Validate before calling
const desc = await fetch(`/api/clusters/${cluster}/topics/${topic}`).then(r => r.json());
if (desc.partitions.some(p => p.leader == null)) {
console.warn(`Topic ${topic} has leaderless partitions; defer offset listing`);
} Type guard
function hasLeaders(topicDesc) {
return topicDesc.partitions.every(p => p.leader != null);
} Try / catch
try {
offsets = await listTopicOffsets(cluster, topic);
} catch (e) {
if (e.message.includes('has no leader')) {
await sleep(backoff); // leader election is usually transient
offsets = await listTopicOffsets(cluster, topic);
} else { throw e; }
} Prevention
- Monitor under-replicated and offline partitions; alert before consumers lag calculations run.
- Use replication factor >= 2 for topics whose offsets you read programmatically.
- Add retry with backoff around offset/lag operations during rolling broker maintenance.
When it happens
Trigger: Calling listTopicOffsets/listOffsets (e.g., GET topic offsets, consumer-group lag calculations) while one or more partitions of the topic have no leader — typically during or right after a broker failure, partition reassignment, or unclean leader election where the metadata still reports leader == null.
Common situations: A broker crashed and the cluster has not finished leader election; replication factor 1 and the only replica (leader) host is down; under-replicated/offline partitions after maintenance or rolling restart; topic reassignment in progress so the partition temporarily has no leader.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Application config isn't valid. Cluster names should be…
- Application config isn't valid. Two clusters can't have the…
- seekTo should be set if seekType is
- Schema Registry is not set for cluster
- ANY operation can be only part of filter
AI-assisted analysis of provectus/kafka-ui@83b5a60cc0 (2026-09-08).
Data as JSON: /api/errors/f0c7669d246b9bdf.
Report an issue: GitHub.
Appendix: source
Thrown at kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java:581
var targetTopics = partitions.stream().map(TopicPartition::topic).collect(Collectors.toSet());
return describeTopicsImpl(targetTopics)
.map(descriptions ->
filterPartitionsWithLeaderCheck(
descriptions.values(), partitions::contains, failOnUnknownLeader));
}
@VisibleForTesting
static Set<TopicPartition> filterPartitionsWithLeaderCheck(Collection<TopicDescription> topicDescriptions,
Predicate<TopicPartition> partitionPredicate,
boolean failOnUnknownLeader) {
var goodPartitions = new HashSet<TopicPartition>();
for (TopicDescription description : topicDescriptions) {
var goodTopicPartitions = new ArrayList<TopicPartition>();
for (TopicPartitionInfo partitionInfo : description.partitions()) {
TopicPartition topicPartition = new TopicPartition(description.name(), partitionInfo.partition());
if (partitionInfo.leader() == null) {
if (failOnUnknownLeader) {
throw new ValidationException(String.format("Topic partition %s has no leader", topicPartition));
} else {
// if ANY of topic partitions has no leader - we have to skip all topic partitions
goodTopicPartitions.clear();
break;
}
}
if (partitionPredicate.test(topicPartition)) {
goodTopicPartitions.add(topicPartition);
}
}
goodPartitions.addAll(goodTopicPartitions);
}
return goodPartitions;
}
// 1. NOTE(!): should only apply for partitions from topics where all partitions have leaders,
// otherwise AdminClient will try to fetch topic metadata, fail and retry infinitely (until timeout)
// 2. NOTE(!): Skips partitions that were not initialized yetView on GitHub (pinned to 83b5a60cc0)