puppetlabs/puppet · error · ArgumentError
A Timestamp cannot be multiplied by %{klass}
Error message
A Timestamp cannot be multiplied by %{klass} What it means
Timespan#* only multiplies by Integer or Float and raises ArgumentError otherwise. Note the message text is misleading in Puppet itself: it says 'A Timestamp cannot be multiplied by ...' even though this is the Timespan#* operator - the string was copied from timestamp.rb. Trust the operand semantics, not the message wording.
Source
Thrown at lib/puppet/pops/time/timespan.rb:163
Timespan.new(@nsecs - o.nsecs)
when Integer, Float
# Subtract seconds
Timespan.new(@nsecs - (o * NSECS_PER_SEC).to_i)
else
raise ArgumentError, _("%{klass} cannot be subtracted from a Timespan") % { klass: a_an_uc(o) }
end
end
def -@
Timespan.new(-@nsecs)
end
def *(o)
case o
when Integer, Float
Timespan.new((@nsecs * o).to_i)
else
raise ArgumentError, _("A Timestamp cannot be multiplied by %{klass}") % { klass: a_an(o) }
end
end
def divmod(o)
case o
when Integer
to_i.divmod(o)
when Float
to_f.divmod(o)
else
raise ArgumentError, _("Can not do modulus on a Timespan using a %{klass}") % { klass: a_an(o) }
end
end
def modulo(o)
divmod(o)[1]
end
View on GitHub (pinned to e227c27540)
Solutions
- Recognize the message wording is a known copy-paste artifact - your receiver is a Timespan and only the right operand is at fault
- Convert the factor: ts * factor.to_i (or .to_f for fractional scaling)
- If multiplying two durations was intentional, redesign - scale by a dimensionless number instead
- Guard with factor.is_a?(Integer) || factor.is_a?(Float) before the expression
Example fix
// before
scaled = span * lookup('scale_factor') # String "2"
// after
f = lookup('scale_factor')
scaled = span * (f.is_a?(String) ? f.to_f : f) Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, "factor must be Numeric, got #{o.class}" unless o.is_a?(Integer) || o.is_a?(Float)
scaled = ts * o Type guard
def numeric_factor?(o) o.is_a?(Integer) || o.is_a?(Float) end
Try / catch
begin ts * factor rescue ArgumentError => e # note: message says 'Timestamp' but receiver is a Timespan (known wording quirk) factor = factor.to_f rescue raise DataError, e.message retry end
Prevention
- Ignore the misleading 'Timestamp' wording in the message - always inspect the right operand
- Coerce scale factors from config with .to_f at load time
- Never multiply two durations; scale by a dimensionless number
When it happens
Trigger: ts * '2', ts * nil, ts * another_timespan, or ts * a Decimal/BigDecimal type from Puppet's type system. Only Integer and Float pass the case statement.
Common situations: Scaling a duration by a factor pulled from Hiera that arrived as a String; developers confused by the error message into thinking their Timestamp is at fault when the receiver is actually a Timespan; multiplying two durations together by mistake.
Related errors
- %{klass} cannot be added to a Timespan
- %{klass} cannot be subtracted from a Timespan
- Can not do modulus on a Timespan using a %{klass}
- A Timespan cannot be divided by %{klass}
- Format specifiers %L and %N denotes fractions and must be us
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/62b6036ccce33402.
Report an issue: GitHub.