prestodb/presto · error · PrestoException

NODE_SELECTION_NOT_SUPPORTED

NODE_SELECTION_NOT_SUPPORTED

Error message

Unsupported node selection strategy for TTL scheduling: %s

What it means

SimpleTtlNodeSelector only supports splits using the NO_PREFERENCE node selection strategy. When TTL-based scheduling is enabled and a split arrives with HARD_AFFINITY or SOFT_AFFINITY, the selector throws NODE_SELECTION_NOT_SUPPORTED because TTL-aware placement cannot honor node affinity preferences. The entry point first checks whether all splits are NO_PREFERENCE and otherwise delegates to simpleNodeSelector; this throw is a defensive per-split check inside the loop.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/execution/scheduler/nodeSelection/SimpleTtlNodeSelector.java:194

        boolean isNodeSelectionStrategyNoPreference = splits.stream().allMatch(split -> split.getNodeSelectionStrategy() == NodeSelectionStrategy.NO_PREFERENCE);
        // Current NodeSelectionStrategy support is limited to NO_PREFERENCE
        if (!isNodeSelectionStrategyNoPreference) {
            return simpleNodeSelector.computeAssignments(splits, existingTasks);
        }

        ImmutableMultimap.Builder<InternalNode, Split> assignment = ImmutableMultimap.builder();
        NodeMap nodeMap = this.nodeMap.get().get();
        NodeAssignmentStats assignmentStats = new NodeAssignmentStats(nodeTaskMap, nodeMap, existingTasks);

        List<InternalNode> eligibleNodes = getEligibleNodes(maxTasksPerStage, nodeMap, existingTasks);
        NodeSelection randomNodeSelection = new RandomNodeSelection(eligibleNodes, minCandidates);

        boolean splitWaitingForAnyNode = false;

        OptionalInt preferredNodeCount = OptionalInt.empty();
        for (Split split : splits) {
            if (split.getNodeSelectionStrategy() != NodeSelectionStrategy.NO_PREFERENCE) {
                throw new PrestoException(
                        NODE_SELECTION_NOT_SUPPORTED,
                        format("Unsupported node selection strategy for TTL scheduling: %s", split.getNodeSelectionStrategy()));
            }

            List<InternalNode> candidateNodes = randomNodeSelection.pickNodes(split);
            if (candidateNodes.isEmpty()) {
                Duration remainingTime = getEstimatedExecutionTimeRemaining();
                if (fallbackToSimpleNodeSelection) {
                    log.warn("No nodes available with enough TTL (%s) to schedule %s. Active nodes %s, falling back to simple node selection.", remainingTime, split, nodeMap.getActiveNodes());
                    return simpleNodeSelector.computeAssignments(splits, existingTasks);
                }

                log.warn("No nodes available with enough TTL (%s) to schedule %s. Active nodes %s", remainingTime, split, nodeMap.getActiveNodes());
                throw new PrestoException(NO_NODES_AVAILABLE, "No nodes available to run query");
            }

            SplitWeight splitWeight = split.getSplitWeight();
            Optional<InternalNodeInfo> chosenNodeInfo = simpleNodeSelector.chooseLeastBusyNode(

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Disable TTL-based scheduling (remove node-scheduler.use-ttl-scheduling=true and related TTL config) so SimpleNodeSelector handles affinity splits.
  2. Identify which connector/stage produces non-NO_PREFERENCE splits from the strategy value in the message and disable bucketed/affinity execution for it (e.g. hive.bucketed-execution=false).
  3. Upgrade Presto: newer versions fall back to simpleNodeSelector for unsupported strategies instead of throwing.
  4. Isolate TTL-scheduled workloads on a separate catalog/cluster from affinity-based workloads.

Example fix

// before (etc/config.properties)
node-scheduler.use-ttl-scheduling=true
// with hive bucketed execution -> NODE_SELECTION_NOT_SUPPORTED

// after
hive.bucketed-execution=false
// or remove node-scheduler.use-ttl-scheduling=true
Defensive patterns

Strategy: validation

Validate before calling

// Check strategy compatibility before enabling TTL scheduling
boolean ttlCompatible = splits.stream()
    .allMatch(s -> s.getNodeSelectionStrategy() == NodeSelectionStrategy.NO_PREFERENCE);
if (useTtlScheduling && !ttlCompatible) {
    // disable TTL scheduling for these splits or reject the workload
}

Type guard

private static boolean supportsTtlScheduling(Split split) {
    return split.getNodeSelectionStrategy() == NodeSelectionStrategy.NO_PREFERENCE;
}

Try / catch

try {
    return ttlNodeSelector.computeAssignments(splits, existingTasks);
} catch (PrestoException e) {
    if (e.getErrorCode().getName().equals("NODE_SELECTION_NOT_SUPPORTED")) {
        return simpleNodeSelector.computeAssignments(splits, existingTasks);
    }
    throw e;
}

Prevention

When it happens

Trigger: TTL-based scheduling enabled (node-scheduler.use-ttl-scheduling / TTL match scheduler config) while query splits use HARD_AFFINITY or SOFT_AFFINITY (e.g. bucketed execution, connector node preferences) and the top-level allMatch(NO_PREFERENCE) guard does not catch the mix.

Common situations: Enabling TTL scheduling on a cluster running bucketed Hive joins (bucketed execution forces HARD_AFFINITY); mixed workloads where some stages produce affinity splits while TTL scheduling is globally on; connector upgrades that start emitting preferred nodes while TTL scheduling is enabled.

Related errors


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