puppetlabs/puppet · error · ArgumentError

%{klass} cannot be added to a Timestamp

Error message

%{klass} cannot be added to a Timestamp

What it means

Timestamp#+ accepts only a Timespan or an Integer/Float (seconds) - adding two absolute points in time is undefined, so Timestamp operands are rejected too. Anything else (including Timestamp, String, nil) raises '%{klass} cannot be added to a Timestamp'. For contrast, Timestamp - Timestamp IS legal and yields a Timespan.

Source

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

    from_time(parsed_time)
  end

  undef_method :-@, :+@, :div, :fdiv, :abs, :abs2, :magnitude # does not make sense on a Timestamp
  if method_defined?(:negative?)
    undef_method :negative?, :positive?
  end
  if method_defined?(:%)
    undef_method :%, :modulo, :divmod
  end

  def +(o)
    case o
    when Timespan
      Timestamp.new(@nsecs + o.nsecs)
    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

View on GitHub (pinned to e227c27540)

Solutions

  1. If you meant 'difference between two timestamps', use subtraction: ts2 - ts1 returns a Timespan
  2. If you meant 'timestamp plus duration', ensure the right side is a Timespan or numeric seconds: ts + Timespan(0, 3600)
  3. Convert string seconds with .to_i / Float()
  4. nil-guard optional durations before the expression

Example fix

// before
elapsed = finished_at + started_at   # both Timestamps -> raise

// after
elapsed = finished_at - started_at    # Timespan (the intended computation)
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

def timestamp_addable?(o)
  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, "#{o.class} not addable to Timestamp (did you mean subtraction for a difference?)"
end

Prevention

When it happens

Trigger: ts + ts2 (both Timestamps), ts + '3600', ts + nil, ts + array. Most common genuine mistake: ts1 + ts2 where the developer wanted the difference (ts2 - ts1).

Common situations: Adding an expiry read from two different sources that both turned out to be Timestamps; Hiera-provided seconds arriving as String; nil from optional parameters; adding Puppet Sensitive or Decimal wrappers.

Related errors


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