{"record":{"id":"4dc01e0ccfe0400c","repo":"puppetlabs/puppet","slug":"from-must-be-less-or-equal-to-to-got-from","errorCode":null,"errorMessage":"'from' must be less or equal to 'to'. Got (#{@from}, #{@to}","messagePattern":"'from' must be less or equal to 'to'\\. Got \\(#(.+?), #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/p_timespan_type.rb","lineNumber":11,"sourceCode":"# frozen_string_literal: true\n\nmodule Puppet::Pops\nmodule Types\n  class PAbstractTimeDataType < PScalarType\n    # @param from [AbstractTime] lower bound for this type. Nil or :default means unbounded\n    # @param to [AbstractTime] upper bound for this type. Nil or :default means unbounded\n    def initialize(from, to = nil)\n      @from = convert_arg(from, true)\n      @to = convert_arg(to, false)\n      raise ArgumentError, \"'from' must be less or equal to 'to'. Got (#{@from}, #{@to}\" unless @from <= @to\n    end\n\n    # Checks if this numeric range intersects with another\n    #\n    # @param o [PNumericType] the range to compare with\n    # @return [Boolean] `true` if this range intersects with the other range\n    # @api public\n    def intersect?(o)\n      instance_of?(o.class) && !(@to < o.numeric_from || o.numeric_to < @from)\n    end\n\n    # Returns the lower bound of the numeric range or `nil` if no lower bound is set.\n    # @return [Float,Integer]\n    def from\n      @from == -Float::INFINITY ? nil : @from\n    end\n\n    # Returns the upper bound of the numeric range or `nil` if no upper bound is set.","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/p_timespan_type.rb#L1-L29","documentation":"PTimespanType and PTimestampType (both PAbstractTimeDataType) are ranged types: initialize converts both bounds via convert_arg (nil/:default become -/+Infinity, Strings are parsed, numbers are seconds) and then requires from <= to. A reversed or overlapping-wrong range raises ArgumentError \"'from' must be less or equal to 'to'\" (the message text is missing its closing parenthesis - cosmetic bug in the source).","triggerScenarios":"Timespan[120, 60] (lower bound of 120 seconds above upper bound of 60), or Timestamp['2024-01-01T00:00:00 UTC', '2023-12-31T23:59:59 UTC']. Any String, Integer, or Float pair where the first bound parses larger than the second, in DSL type expressions or Ruby PTimespanType.new(from, to).","commonSituations":"Bounds supplied as user variables in the wrong order (e.g. expiry window computed as [end, start]); DST or timezone shifts making a previously valid timestamp range inverted; literals written largest-first out of habit.","solutions":["Swap the arguments so the earlier/lower value comes first: Timespan[60, 120]","When bounds come from variables, normalize with min/max (or [a, b].minmax) before constructing the type","Leave a bound as default/unbounded rather than passing an inverted sentinel value"],"exampleFix":"# before\n$window = Timespan[120, 60]                                   # from > to\n$range  = Timestamp['2024-06-01T00:00:00 UTC', '2024-01-01T00:00:00 UTC']\n\n# after\n$window = Timespan[60, 120]\n$from, $to = [$start, $end].minmax                            # normalize variable bounds\n$range  = Timestamp[$from, $to]","handlingStrategy":"validation","validationCode":"# normalize bounds before constructing the ranged type\nfrom, to = [from_bound, to_bound].minmax  # after converting to comparable Timespan/Timestamp\nraise 'inverted range' if from && to && from > to\nTimespan.new(from, to)  # or Timespan[from, to] in DSL","typeGuard":"def valid_time_bounds?(from, to)\n  f = from.nil? || from == :default ? -Float::INFINITY : from.to_f\n  t = to.nil? || to == :default ? Float::INFINITY : to.to_f\n  f <= t\nend","tryCatchPattern":"begin\n  Timespan[from_arg, to_arg]\nrescue ArgumentError => e\n  raise unless e.message =~ /'from' must be less or equal to 'to'/\n  Timespan[to_arg, from_arg]  # deliberate swap only when mis-ordering is provably the cause\nend","preventionTips":["Compute window bounds with min/max before building types from user data","Watch timezone/DST handling when parsing timestamp bounds from strings","Leave a bound unset (default) instead of passing sentinel values"],"tags":["puppet","timespan","timestamp","range","validation"],"backgroundTag":"invalid-range-bounds","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}