apache/flink · error · IllegalArgumentException

Cannot compare specified resources with UNKNOWN resources.

Error message

Cannot compare specified resources with UNKNOWN resources.

What it means

Thrown by ResourceSpec.lessThanOrEqual() when exactly one of the two compared ResourceSpec instances is the UNKNOWN constant (and the other is a concrete resource spec). UNKNOWN is a sentinel meaning 'resource requirements not specified'; Flink treats it as semantically uncomparable because you cannot assert a concrete spec is <= an unknown one or vice-versa. The comparison only succeeds if both are UNKNOWN (returns true) or both are concrete.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/ResourceSpec.java:241

            throw new UnsupportedOperationException();
        }
    }

    /**
     * Checks the current resource less than or equal with the other resource by comparing all the
     * fields in the resource.
     *
     * @param other The resource to compare
     * @return True if current resource is less than or equal with the other resource, otherwise
     *     return false.
     */
    public boolean lessThanOrEqual(final ResourceSpec other) {
        checkNotNull(other, "Cannot compare with null resources");

        if (this.equals(UNKNOWN) && other.equals(UNKNOWN)) {
            return true;
        } else if (this.equals(UNKNOWN) || other.equals(UNKNOWN)) {
            throw new IllegalArgumentException(
                    "Cannot compare specified resources with UNKNOWN resources.");
        }

        int cmp1 = this.cpuCores.getValue().compareTo(other.getCpuCores().getValue());
        int cmp2 = this.taskHeapMemory.compareTo(other.taskHeapMemory);
        int cmp3 = this.taskOffHeapMemory.compareTo(other.taskOffHeapMemory);
        int cmp4 = this.managedMemory.compareTo(other.managedMemory);
        if (cmp1 <= 0 && cmp2 <= 0 && cmp3 <= 0 && cmp4 <= 0) {
            for (ExternalResource resource : extendedResources.values()) {
                if (!other.extendedResources.containsKey(resource.getName())
                        || other.extendedResources
                                        .get(resource.getName())
                                        .getValue()
                                        .compareTo(resource.getValue())
                                < 0) {
                    return false;
                }
            }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure both ResourceSpec operands are concrete (built via the builder with explicit values) or both are UNKNOWN before calling lessThanOrEqual().
  2. Guard the call: if (spec.equals(ResourceSpec.UNKNOWN) || other.equals(ResourceSpec.UNKNOWN)) skip the comparison or handle as a special case.
  3. Replace the UNKNOWN operand with a concrete ResourceSpec.DEFAULT or a builder-constructed spec matching your slot's resources.
  4. When chaining operators, make sure all operators in the chain either have explicit resource specs or all use the default.

Example fix

// before
ResourceSpec a = ResourceSpec.newBuilder().setCpuCores(1.0).setTaskHeapMemoryInMB(100).build();
boolean fits = a.lessThanOrEqual(ResourceSpec.UNKNOWN); // throws

// after
ResourceSpec slotSpec = ResourceSpec.newBuilder().setCpuCores(2.0).setTaskHeapMemoryInMB(512).build();
boolean fits = a.lessThanOrEqual(slotSpec); // works: concrete vs concrete
Defensive patterns

Strategy: validation

Validate before calling

boolean isSafeToCompare(ResourceSpec a, ResourceSpec b) {
    boolean aUnknown = a.equals(ResourceSpec.UNKNOWN);
    boolean bUnknown = b.equals(ResourceSpec.UNKNOWN);
    return (aUnknown && bUnknown) || (!aUnknown && !bUnknown);
}
// Before calling a.lessThanOrEqual(b):
if (!isSafeToCompare(a, b)) {
    // handle the unknown-vs-concrete case explicitly
}

Type guard

static boolean isConcrete(ResourceSpec spec) {
    return spec != null && !spec.equals(ResourceSpec.UNKNOWN);
}

Try / catch

try {
    boolean fits = a.lessThanOrEqual(b);
} catch (IllegalArgumentException e) {
    // one side is UNKNOWN; handle by treating as unlimited or failing the slot fit
    log.warn("Cannot compare ResourceSpec {} with {}", a, b);
}

Prevention

When it happens

Trigger: Calling resourceSpecA.lessThanOrEqual(resourceSpecB) where one spec was built with explicit CPU/memory values and the other is ResourceSpec.UNKNOWN (or ResourceSpec.DEFAULT, which aliases UNKNOWN). Happens during slot/resource fitting when the scheduler or optimizer compares an operator's ResourceSpec against a provisioned slot's ResourceSpec, and one side was never configured.

Common situations: Custom operators or transformations that do not specify resource hints (defaults to UNKNOWN) are compared against explicitly configured slots. Mixing ResourceSpec.ZERO or a builder-constructed spec with default operators in a chain that triggers a lessThanOrEqual check. Resource-aware scheduling misconfiguration where only some operators have resource specs set.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/8ee63a0e5529ef24. Report an issue: GitHub.