puppetlabs/puppet · error · ArgumentError

'from' must be less or equal to 'to'. Got (#{from}, #{to}

Error message

'from' must be less or equal to 'to'. Got (#{from}, #{to}

What it means

Puppet's type system models numeric ranges (Integer[from, to], Float[from, to]) with subclasses of PNumericType. The constructor rewrites nil or :default to -/+Float::INFINITY and then enforces the invariant from <= to, because an inverted range is meaningless. In manifests this surfaces as Integer[10, 2] or Float[$a, $b] with $a > $b; from Ruby it comes from PIntegerType.new(10, 2). The message prints both offending bounds.

Source

Thrown at lib/puppet/pops/types/types.rb:943

          end
        end
      end

      def on_error(from, abs = false)
        if from.is_a?(String)
          _("The string '%{str}' cannot be converted to Numeric") % { str: from }
        else
          t = TypeCalculator.singleton.infer(from).generalize
          _("Value of type %{type} cannot be converted to Numeric") % { type: t }
        end
      end
    end
  end

  def initialize(from, to = Float::INFINITY)
    from = -Float::INFINITY if from.nil? || from == :default
    to = Float::INFINITY if to.nil? || to == :default
    raise ArgumentError, "'from' must be less or equal to 'to'. Got (#{from}, #{to}" if from > to

    @from = from
    @to = to
  end

  # Checks if this numeric range intersects with another
  #
  # @param o [PNumericType] the range to compare with
  # @return [Boolean] `true` if this range intersects with the other range
  # @api public
  def intersect?(o)
    instance_of?(o.class) && !(@to < o.numeric_from || o.numeric_to < @from)
  end

  # Returns the lower bound of the numeric range or `nil` if no lower bound is set.
  # @return [Float,Integer]
  def from
    @from == -Float::INFINITY ? nil : @from

View on GitHub (pinned to e227c27540)

Solutions

  1. Order the bounds so the lower value comes first: Integer[2, 10] instead of Integer[10, 2].
  2. If the pair comes from user input, sort it before use: $bounds = [$a, $b].sort; Integer[$bounds[0], $bounds[1]].
  3. Use undef (DSL) or nil / :default (Ruby) for an open end instead of a number, e.g. Integer[1, default].
  4. In Ruby, validate from <= to before calling PIntegerType.new and raise your own descriptive error.

Example fix

# before (Puppet DSL)
Integer[$high, $low]   # ArgumentError: 'from' must be less or equal to 'to' when $high > $low

# after
$bounds = [$low, $high].sort
Integer[$bounds[0], $bounds[1]]
Defensive patterns

Strategy: validation

Validate before calling

# Ruby: normalize and check before constructing
from = -Float::INFINITY if from.nil? || from == :default
to   =  Float::INFINITY if to.nil?   || to == :default
raise ArgumentError, "inverted range (#{from}, #{to})" unless from <= to
PIntegerType.new(from, to)

Type guard

def valid_numeric_range?(from, to)
  [from, to].all? { |v| v.nil? || v == :default || v.is_a?(Numeric) } &&
    (from.nil? || from == :default || to.nil? || to == :default || from <= to)
end

Try / catch

begin
  PIntegerType.new(from, to)
rescue ArgumentError
  from, to = [from, to].minmax   # both Numeric: normalize inverted bounds
  retry
end

Prevention

When it happens

Trigger: Writing Integer[5, 1] or Float[10, 0.5] in Puppet DSL; calling PIntegerType.new(from, to) / PFloatType.new(from, to) in Ruby with from > to; range endpoints taken from variables, facts or class parameters that arrive in the wrong order (for example Integer[$port_max, $port_min]).

Common situations: A manifest parameter pair meant to be min/max gets swapped by the user; computed ranges (port windows, pagination) that are never sorted before use; Ruby wrapper code feeding unvalidated input straight into the type constructor; copy-pasting an example with the bounds reversed.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/c1316d096af2390b. Report an issue: GitHub.