puppetlabs/puppet · error · Puppet::Error

Repeat must be 1 unless periodmatch is 'distance', not '%{pe

Error message

Repeat must be 1 unless periodmatch is 'distance', not '%{period}'

What it means

A schedule's `repeat` > 1 is only meaningful when `periodmatch` is 'distance' (periods measured as distance since epoch). The validate raises Puppet::Error "Repeat must be 1 unless periodmatch is 'distance'" (lib/puppet/type/schedule.rb:292) when repeat != 1 and periodmatch is set to something else — in practice 'number' (calendar-matched periods).

Source

Thrown at lib/puppet/type/schedule.rb:292

    newparam(:repeat) do
      desc "How often a given resource may be applied in this schedule's `period`.
        Must be an integer."

      defaultto 1

      validate do |value|
        unless value.is_a?(Integer) or value =~ /^\d+$/
          raise Puppet::Error,
                _("Repeat must be a number")
        end

        # This implicitly assumes that 'periodmatch' is distance -- that
        # is, if there's no value, we assume it's a valid value.
        return unless @resource[:periodmatch]

        if value != 1 and @resource[:periodmatch] != :distance
          raise Puppet::Error,
                _("Repeat must be 1 unless periodmatch is 'distance', not '%{period}'") % { period: @resource[:periodmatch] }
        end
      end

      munge do |value|
        value = Integer(value) unless value.is_a?(Integer)

        value
      end

      def match?(previous, now)
        true
      end
    end

    newparam(:weekday) do
      desc <<-EOT
        The days of the week in which the schedule should be valid.

View on GitHub (pinned to e227c27540)

Solutions

  1. Set `periodmatch => distance` (the default) when using repeat > 1
  2. Or keep `repeat => 1` and change `period` granularity instead
  3. Remove the explicit periodmatch if you actually want distance semantics

Example fix

# before
schedule { 'backups':
  period      => daily,
  periodmatch => number,
  repeat      => 3,
}

# after
schedule { 'backups':
  period      => daily,
  periodmatch => distance,
  repeat      => 3,
}
Defensive patterns

Strategy: validation

Validate before calling

if $repeat != 1 and $periodmatch != undef and $periodmatch != 'distance' {
  fail("repeat > 1 requires periodmatch => distance, got '${periodmatch}'")
}

Type guard

def repeat_periodmatch_ok?(repeat, periodmatch)
  repeat == 1 || periodmatch.to_s == 'distance'
end

Try / catch

begin
  Puppet::Type.type(:schedule).new(
    name: 'x', period: :daily, periodmatch: :number, repeat: 3
  )
rescue Puppet::Error => e
  raise unless e.message.include?('periodmatch')
  # switch periodmatch to :distance or set repeat to 1
end

Prevention

When it happens

Trigger: `schedule { 'x': period => daily, periodmatch => number, repeat => 3 }`; setting periodmatch => number in a shared schedule define while another layer sets repeat.

Common situations: Users switching periodmatch to 'number' for calendar semantics while keeping a repeat count; module upgrades that exposed both knobs.

Related errors


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