kestra-io/kestra · error · PebbleException

Could not perform less than or equals comparison

Error message

Could not perform less than or equals comparison

What it means

Thrown by the custom LessThanEqualsExpression Pebble node when the '<=' comparison cannot be evaluated. The expression tries string comparison first, then OperatorUtils.lte for numbers; if lte throws due to incomparable operand types, the exception is wrapped with this message.

Source

Thrown at core/src/main/java/io/kestra/core/runners/pebble/expression/LessThanEqualsExpression.java:24

import io.pebbletemplates.pebble.template.PebbleTemplateImpl;
import io.pebbletemplates.pebble.utils.OperatorUtils;

public class LessThanEqualsExpression extends BinaryExpression<Boolean> {
    @Override
    public Boolean evaluate(PebbleTemplateImpl self, EvaluationContextImpl context) {
        Object left = this.getLeftExpression().evaluate(self, context);
        Object right = this.getRightExpression().evaluate(self, context);

        // add support for string comparison
        if (left instanceof String sLeft && right instanceof String sRight) {
            return sLeft.compareTo(sRight) <= 0;
        }

        // default implementation from io.pebbletemplates.pebble.node.expression.LessThanExpression
        try {
            return OperatorUtils.lte(left, right);
        } catch (Exception ex) {
            throw new PebbleException(
                ex, "Could not perform less than or equals comparison", this.getLineNumber(), self
                    .getName()
            );
        }
    }
}

View on GitHub (pinned to 823fada927)

Solutions

  1. Confirm both operands are strings or numbers before comparison.
  2. Default the variable to a numeric value: '{{ (vars.metric ?? 0) <= 100 }}'.
  3. Add explicit type validation in the upstream task to guarantee the output type.

Example fix

{# before #}
{% if outputs.task.count <= max_items %}

{# after #}
{% if (outputs.task.count ?? 0) <= (max_items ?? 100) %}
Defensive patterns

Strategy: validation

Validate before calling

{# Default both sides to a numeric value before using <= #}
{% set left = (vars.metric ?? 0) %}
{% set right = (vars.ceiling ?? 100) %}
{% if left <= right %}...{% endif %}

Type guard

{# Ensure operand is not null or complex before comparing #}
{% set safe_val = outputs.task.count ?? 0 %}
{% if safe_val is not null and safe_val is not iterable %}
  {{ safe_val <= max_items }}
{% endif %}

Prevention

When it happens

Trigger: Using '<=' with mismatched or non-comparable operand types: '{{ mylist <= 10 }}', '{{ null <= 5 }}', '{{ somemap <= "x" }}'. One side being null while the other is non-string is the most common trigger.

Common situations: Flow conditions comparing outputs that may be null or complex. Threshold checks where the monitored value comes from an upstream task that could produce an unexpected type. Template logic written assuming a numeric output that occasionally resolves to an object.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/0cf2eb4fd563fe06. Report an issue: GitHub.