prestodb/presto · critical · ResourceManagerInconsistentException

%s nodes found in discovery vs. %s nodes found in heartbeats

Error message

%s nodes found in discovery vs. %s nodes found in heartbeats

What it means

ResourceManagerClusterStateProvider validates that every coordinator known to discovery is also seen in the node-status heartbeats the resource manager receives. If the discovered coordinator set and the heartbeated coordinator set differ (or there are no coordinators at all), the cluster view is inconsistent, so getClusterResourceGroups throws ResourceManagerInconsistentException instead of returning stale resource-group state.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/resourcemanager/ResourceManagerClusterStateProvider.java:373

    public Map<String, MemoryInfo> getWorkerMemoryInfo()
    {
        return nodeStatuses.entrySet().stream().collect(toImmutableMap(e -> {
            String nodeIdentifier = e.getValue().getNodeStatus().getNodeId();
            String nodeHost = URI.create(e.getValue().getNodeStatus().getExternalAddress()).getHost();
            return nodeIdentifier + " [" + nodeHost + "]";
        }, e -> e.getValue().getNodeStatus().getMemoryInfo()));
    }

    private void validateCoordinatorConsistency()
    {
        Set<String> coordinators = internalNodeManager.getCoordinators().stream().map(InternalNode::getNodeIdentifier).collect(toImmutableSet());
        Set<String> heartbeatedCoordinatorNodes = nodeStatuses.values().stream()
                .map(InternalNodeState::getNodeStatus)
                .filter(NodeStatus::isCoordinator)
                .map(NodeStatus::getNodeId)
                .collect(toImmutableSet());
        if (!(Sets.difference(coordinators, heartbeatedCoordinatorNodes).isEmpty() && !coordinators.isEmpty())) {
            throw new ResourceManagerInconsistentException(format("%s nodes found in discovery vs. %s nodes found in heartbeats", coordinators.size(), heartbeatedCoordinatorNodes.size()));
        }
    }

    private static class CoordinatorResourceGroupState
    {
        private final String nodeId;
        private final long lastHeartbeatInMillis;
        private final List<ResourceGroupRuntimeInfo> resourceGroups;

        public CoordinatorResourceGroupState(
                String nodeId,
                long lastHeartbeatInMillis,
                List<ResourceGroupRuntimeInfo> resourceGroups)
        {
            this.nodeId = requireNonNull(nodeId, "nodeId is null");
            this.lastHeartbeatInMillis = lastHeartbeatInMillis;
            this.resourceGroups = requireNonNull(resourceGroups, "resourceGroups is null");
        }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Check every coordinator process is up and heartbeating to the resource manager (logs on both sides)
  2. Verify network connectivity between each coordinator and the resource manager (ports, firewalls, DNS)
  3. Confirm all coordinators share the same discovery URI / resource-manager configuration
  4. If transient (startup or rolling restart), retry after heartbeats converge
  5. If a coordinator was removed, wait for its discovery entry to expire or clean stale discovery state
Defensive patterns

Strategy: try-catch

Validate before calling

// gauge cluster health before scheduling
boolean consistent = discoveredCoordinators.equals(heartbeatedCoordinators) && !discoveredCoordinators.isEmpty();

Try / catch

try {
    provider.getClusterResourceGroups();
} catch (ResourceManagerInconsistentException e) {
    log.warn("Discovery/heartbeat coordinator mismatch: {}", e.getMessage());
    // retry after heartbeat interval or report unhealthy cluster
}

Prevention

When it happens

Trigger: validateCoordinatorConsistency, called from getClusterResourceGroups, throws when Sets.difference(coordinators, heartbeatedCoordinatorNodes) is non-empty or when the discovered coordinators set is empty — i.e. a coordinator appears in discovery but its NodeStatus heartbeats have not reached this resource manager.

Common situations: A coordinator crashed or was killed but its discovery entry has not expired; network partition between a coordinator and the resource manager blocking heartbeats; rolling restart/redeployment where discovery and heartbeat state are momentarily out of sync; misconfigured discovery URI so a coordinator registers in discovery but heartbeats elsewhere; very fresh cluster where heartbeats have not all arrived yet.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/4107d9508c533426. Report an issue: GitHub.