SonarSource/sonarqube · error · IllegalStateException

Distributed cluster action in cluster nodes (other nodes…

Error message

Distributed cluster action in cluster nodes  (other nodes may have timed out)

What it means

DistributedAnswer.propagateExceptions reports failures of a Hazelcast distributed action across cluster members. When some members returned a failure (failedMembers non-empty), it throws IllegalStateException naming those nodes and attaching the first failure as the cause.

Solutions

  1. Inspect the attached cause (first failed member's exception) and the named nodes' logs for the root error.
  2. Restart or repair the failing cluster member(s) listed in the message.
  3. Verify all nodes run the same SonarQube version and plugins to avoid handling incompatibilities.

Example fix

// operator: check failing node
kubectl logs <failed-node-pod> | tail -100  // find the root exception reported as cause
// then restart the failing member so it re-joins the cluster
Defensive patterns

Strategy: try-catch

Validate before calling

List<Member> healthy = cluster.getMembers().stream()
  .filter(m -> m.getHealth() == MemberHealth.HEALTHY)
  .collect(Collectors.toList());
if (healthy.size() < expectedQuorum) {
  throw new IllegalStateException("Refusing distributed action: insufficient healthy members");
}

Try / catch

try {
  distributedAnswer.propagateExceptions();
} catch (IllegalStateException e) {
  logger.error("Cluster action failed on nodes: {}; cause: {}", e.getMessage(), e.getCause());
  // alert ops / retry after repairing nodes
}

Prevention

When it happens

Trigger: Executing a cluster-wide operation (e.g. via HazelcastMemberAddressables/distributed call) where one or more member nodes answered with an exception; propagateExceptions() is then called to surface the error to the caller.

Common situations: A node failing to apply a cluster operation due to local errors (disk full, deserialization failure, internal error) while others succeed; mixed-version cluster where one node cannot handle the action.

Understand the failure class

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/1f816ee4277ece86. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-process/src/main/java/org/sonar/process/cluster/hz/DistributedAnswer.java:82

  public void setAnswer(Member member, T answer) {
    this.answers.put(member, answer);
  }

  public void setTimedOut(Member member) {
    this.timedOutMembers.add(member);
  }

  public void setFailed(Member member, Exception e) {
    failedMembers.put(member, e);
  }

  public void propagateExceptions() {
    if (!failedMembers.isEmpty()) {
      String failedMemberNames = failedMembers.keySet().stream()
        .map(m -> m.getAttribute(NODE_NAME.getKey()))
        .collect(Collectors.joining(", "));
      throw new IllegalStateException("Distributed cluster action in cluster nodes " + failedMemberNames + " (other nodes may have timed out)",
        failedMembers.values().iterator().next());
    }

    if (!timedOutMembers.isEmpty()) {
      String timedOutMemberNames = timedOutMembers.stream()
        .map(m -> m.getAttribute(NODE_NAME.getKey()))
        .collect(Collectors.joining(", "));
      throw new IllegalStateException("Distributed cluster action timed out in cluster nodes " + timedOutMemberNames);
    }
  }

  /**
   * Returns any answer. No guarantees are made on the order. Use this method if you only expect exactly one answer.
   * @return the first answer, if any
   */
  public Optional<T> getSingleAnswer() {
    return answers.values().stream().findFirst();
  }

View on GitHub (pinned to 184c821202)