puppetlabs/puppet · error · ArgumentError

A required parameter cannot be added after an optional param

Error message

A required parameter cannot be added after an optional parameter

What it means

In a dispatch DSL block, param declares a required positional parameter. The builder tracks optionality with @min and @max; when @min != @max an optional parameter was already declared. A required parameter after an optional one is impossible to bind at call time, so Puppet rejects it at definition time with this ArgumentError.

Source

Thrown at lib/puppet/functions.rb:415

    # @api private
    def initialize(dispatcher, all_callables, loader)
      @all_callables = all_callables
      @dispatcher = dispatcher
      @loader = loader
    end

    # Defines a required positional parameter with _type_ and _name_.
    #
    # @param type [String] The type specification for the parameter.
    # @param name [Symbol] The name of the parameter. This is primarily used
    #   for error message output and does not have to match an implementation
    #   method parameter.
    # @return [Void]
    #
    # @api public
    def param(type, name)
      internal_param(type, name)
      raise ArgumentError, _('A required parameter cannot be added after an optional parameter') if @min != @max

      @min += 1
      @max += 1
    end
    alias required_param param

    # Defines an optional positional parameter with _type_ and _name_.
    # May not be followed by a required parameter.
    #
    # @param type [String] The type specification for the parameter.
    # @param name [Symbol] The name of the parameter. This is primarily used
    #   for error message output and does not have to match an implementation
    #   method parameter.
    # @return [Void]
    #
    # @api public
    def optional_param(type, name)
      internal_param(type, name)

View on GitHub (pinned to e227c27540)

Solutions

  1. Reorder the declarations: all param entries first, then optional_param entries.
  2. If the new argument must be last and mandatory, promote the earlier optional_param to param as well (note: breaking change for callers).
  3. If both call shapes must stay supported, declare two separate dispatch blocks with different arities instead.

Example fix

# before
 dispatch :run do
   optional_param 'String', :suffix
   param 'String', :base       # raises: required after optional
 end

# after: required parameters come first
 dispatch :run do
   param 'String', :base
   optional_param 'String', :suffix
 end
Defensive patterns

Strategy: validation

Validate before calling

# Review-time ordering rule: required params first, then optional, then repeated, then block
# CI grep: fail if an optional_param line appears before a param line in one dispatch
! grep -Pzo 'dispatch[^}]*optional_param[^}]*\n[^}]*\sparam ' lib/puppet/functions/**/*.rb

Prevention

When it happens

Trigger: dispatch :m do optional_param 'String', :b; param 'String', :a end. The required :a is declared after the optional :b, so the raise fires.

Common situations: Adding a new mandatory argument to a signature that already ends with optional arguments; merges or edits that reorder param blocks mechanically.

Related errors


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