puppetlabs/puppet · error · ArgumentError

%{klass} cannot be subtracted from a Timestamp

Error message

%{klass} cannot be subtracted from a Timestamp

What it means

Timestamp#- accepts a Timestamp (result: Timespan difference), a Timespan (result: Timestamp), or Integer/Float seconds (result: Timestamp). Everything else raises '%{klass} cannot be subtracted from a Timestamp'. This mirrors Timespan#- but, unlike it, does allow Timestamp operands because two points define a duration.

Source

Thrown at lib/puppet/pops/time/timestamp.rb:150

    when Integer, Float
      Timestamp.new(@nsecs + (o * NSECS_PER_SEC).to_i)
    else
      raise ArgumentError, _("%{klass} cannot be added to a Timestamp") % { klass: a_an_uc(o) }
    end
  end

  def -(o)
    case o
    when Timestamp
      # Diff between two timestamps is a timespan
      Timespan.new(@nsecs - o.nsecs)
    when Timespan
      Timestamp.new(@nsecs - o.nsecs)
    when Integer, Float
      # Subtract seconds
      Timestamp.new(@nsecs - (o * NSECS_PER_SEC).to_i)
    else
      raise ArgumentError, _("%{klass} cannot be subtracted from a Timestamp") % { klass: a_an_uc(o) }
    end
  end

  def format(format, timezone = nil)
    self.class.format_time(format, to_time, timezone)
  end

  def to_s
    format(DEFAULT_FORMATS[0])
  end

  def to_time
    ::Time.at(to_r).utc
  end
end
end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Convert numeric strings first: ts - margin.to_i
  2. Wrap foreign duration objects into a Puppet Timespan before subtracting
  3. Default optional parameters: (params['margin'] || 0)
  4. Add an explicit case guard for Timestamp/Timespan/Integer/Float with a domain-specific error

Example fix

// before
remaining = deadline - lookup('margin')   # String "300"

// after
remaining = deadline - Integer(lookup('margin'))
Defensive patterns

Strategy: type-guard

Validate before calling

ok = o.is_a?(Puppet::Pops::Time::Timestamp) || o.is_a?(Puppet::Pops::Time::Timespan) || o.is_a?(Integer) || o.is_a?(Float)
raise ArgumentError, "cannot subtract #{o.class} from Timestamp" unless ok
ts - o

Type guard

def timestamp_subtractable?(o)
  o.is_a?(Puppet::Pops::Time::Timestamp) || o.is_a?(Puppet::Pops::Time::Timespan) ||
    o.is_a?(Integer) || o.is_a?(Float)
end

Try / catch

begin
  ts - o
rescue ArgumentError => e
  raise DataError, "bad subtrahend #{o.inspect} for Timestamp"
end

Prevention

When it happens

Trigger: ts - '10', ts - nil, ts - [60], ts - some_array or hash, or a Puppet Decimal/Sensitive wrapper on the right side.

Common situations: Subtracting a TTL or margin loaded from config that arrived as String; nil when an optional 'since' parameter was not set; passing a duration object from another library (ActiveSupport::Duration) that is not a Puppet Timespan.

Related errors


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