provectus/kafka-ui · warning · ValidationException

Replication factor already equals requested

Error message

Replication factor already equals requested

What it means

TopicsService.getPartitionsReassignments computes a new partition assignment to change a topic's replication factor. If the topic's current replication factor already equals the requested one, no reassignment is possible or needed, and a ValidationException with 'Replication factor already equals requested' is thrown before any assignment is produced.

Solutions

  1. Check the topic's current replication factor before calling the API and only send a different value
  2. Delete the redundant call or make it a no-op when target equals current
  3. Verify the correct topic name was used (a same-factor topic implies no change was intended)
  4. If an increase/decrease was intended, confirm broker count allows the target factor

Example fix

// before
int targetFactor = topic.getReplicationFactor(); // equals current
// after
int current = describeTopic(topicName).replicationFactor();
int targetFactor = Math.min(current + 1, brokers.size());
Defensive patterns

Strategy: validation

Validate before calling

// Java (caller)
int current = topicsService.getTopicDetails(cluster, topicName)
    .getTopicDescription().partitions().get(0).replicas().size();
if (targetFactor == current) {
  throw new IllegalArgumentException("Replication factor already " + current + "; nothing to change");
}

Try / catch

try {
  topicsService.changeReplicationFactor(cluster, topicName, targetFactor);
} catch (ValidationException e) {
  if (e.getMessage().contains("already equals requested")) {
    log.info("No-op: replication factor already {}", targetFactor); // treat as success
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling the changeReplicationFactor API (PUT topic replication factor) with a target replication factor identical to the topic's current replication factor.

Common situations: Re-submitting an already-applied replication factor change; scripted/CI jobs that compute a target factor matching current config; copy-pasted requests using the same factor as the topic.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of provectus/kafka-ui@83b5a60cc0 (2026-09-08). Data as JSON: /api/errors/3fad8a776053e979. Report an issue: GitHub.

Appendix: source

Thrown at kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java:349

        // Iterate brokers and try to remove them from assignment
        // while partition replicas count != requested replication factor
        for (Integer broker : brokersUsageList) {
          // Check is the broker the leader of partition
          if (!topic.getPartitions().get(partition).getLeader()
              .equals(broker)) {
            brokers.remove(broker);
            brokersUsage.merge(broker, -1, Integer::sum);
          }
          if (brokers.size() == replicationFactorChange.getTotalReplicationFactor()) {
            break;
          }
        }
        if (brokers.size() != replicationFactorChange.getTotalReplicationFactor()) {
          throw new ValidationException("Something went wrong during removing replicas");
        }
      }
    } else {
      throw new ValidationException("Replication factor already equals requested");
    }

    // Return result map
    return currentAssignment.entrySet().stream().collect(toMap(
        e -> new TopicPartition(topic.getName(), e.getKey()),
        e -> Optional.of(new NewPartitionReassignment(e.getValue()))
    ));
  }

  private Map<Integer, List<Integer>> getCurrentAssignment(InternalTopic topic) {
    return topic.getPartitions().values().stream()
        .collect(toMap(
            InternalPartition::getPartition,
            p -> p.getReplicas().stream()
                .map(InternalReplica::getBroker)
                .collect(toList())
        ));
  }

View on GitHub (pinned to 83b5a60cc0)