puppetlabs/puppet · error · ArgumentError

before_action takes three arguments, action, args, and optio

Error message

before_action takes three arguments, action, args, and options

What it means

OptionBuilder#before_action invokes the hook as `call(action, args, options)` and therefore enforces `block.arity == 3` (lib/puppet/interface/option_builder.rb:55). Blocks with fewer (or more) declared parameters fail, as do splat blocks like `{ |*a| }` whose arity is negative. Declare exactly three parameters.

Source

Thrown at lib/puppet/interface/option_builder.rb:55

  # main action code. This is most commonly used to validate an option.
  # @yieldparam action [Puppet::Interface::Action] The action being
  #   invoked
  # @yieldparam args [Array] The arguments given to the action
  # @yieldparam options [Hash<Symbol=>Object>] Any options set
  # @api public
  # @dsl Faces
  def before_action(&block)
    unless block
      # TRANSLATORS 'before_action' is a method name and should not be translated
      raise ArgumentError, _("%{option} before_action requires a block") % { option: @option }
    end
    if @option.before_action
      # TRANSLATORS 'before_action' is a method name and should not be translated
      raise ArgumentError, _("%{option} already has a before_action set") % { option: @option }
    end
    unless block.arity == 3 then
      # TRANSLATORS 'before_action' is a method name and should not be translated
      raise ArgumentError, _("before_action takes three arguments, action, args, and options")
    end

    @option.before_action = block
  end

  # Sets a block to be executed after an action is invoked.
  # !(see before_action)
  # @api public
  # @dsl Faces
  def after_action(&block)
    unless block
      # TRANSLATORS 'after_action' is a method name and should not be translated
      raise ArgumentError, _("%{option} after_action requires a block") % { option: @option }
    end
    if @option.after_action
      # TRANSLATORS 'after_action' is a method name and should not be translated
      raise ArgumentError, _("%{option} already has an after_action set") % { option: @option }
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Declare all three parameters: `before_action { |action, args, options| ... }`
  2. If you only need one value, accept three and underscore the unused: `|_action, _args, options|`
  3. When constructing the hook as an object, assert `hook.arity == 3` before passing it with `&hook`

Example fix

# before
before_action { |action, args| validate(args) }

# after
before_action { |action, args, options| validate(args) }
Defensive patterns

Strategy: validation

Validate before calling

hook = proc { |action, args, options| validate(args) }
raise ArgumentError, 'before_action hook must take exactly 3 args' unless hook.arity == 3
before_action(&hook)

Prevention

When it happens

Trigger: `before_action { |action, args| ... }` (arity 2); `before_action { |*a| ... }` (arity -1); a proc with any non-exact signature that does not evaluate to 3.

Common situations: Refactoring a hook down to two params; copying a 2-arg hook from another framework; 'catch-all' splat style blocks.

Related errors


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