puppetlabs/puppet · error · ArgumentError
%{option} before_action requires a block
Error message
%{option} before_action requires a block What it means
Puppet::Interface::OptionBuilder#before_action, used inside `option ... do ... end` blocks in the Faces DSL, requires a block literal (lib/puppet/interface/option_builder.rb:47). Calling it with no block — a bare `before_action` — raises ArgumentError at face-load time. `%{option}` renders the Option being built, i.e. its dashed name such as --environment.
Source
Thrown at lib/puppet/interface/option_builder.rb:47
unless private_method_defined? dsl
define_method(dsl) do |value| @option.send(setter, value) end
end
end
# Override some methods that deal in blocks, not objects.
# Sets a block to be executed when an action is invoked before the
# 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)View on GitHub (pinned to e227c27540)
Solutions
- Always pass a literal block: `before_action { |action, args, options| ... }`
- To reuse a named method, wrap it: `before_action { |*a| my_validator(*a) }`
- If the hook is conditional, guard the whole call: `before_action { ... } if hook_needed`
Example fix
# before
option "--verbose" do
before_action
end
# after
option "--verbose" do
before_action do |action, args, options|
raise "--verbose not supported here" if options[:verbose]
end
end Defensive patterns
Strategy: validation
Validate before calling
# when the hook comes from a variable raise ArgumentError, 'before_action needs a block' if hook.nil? before_action(&hook) # inside the option block
Prevention
- Always write `before_action do |action, args, options| ... end` with a literal block
- Check hook variables for nil before passing them with `&`
- Name helper methods differently from DSL methods to avoid bare-call mistakes
When it happens
Trigger: `option '--foo' do before_action end` (no block); `before_action(&hook)` where hook is nil; intending to call a helper method literally named before_action.
Common situations: Refactoring a block body into a method and leaving a bare call; passing an optional hook variable that was never set; misunderstanding the DSL as method-reference style.
Related errors
- %{option} after_action requires a block
- %{option} default_to requires a block
- %{name} can't be optional and have a default value
- default value for %{name} is a %{class_name}, not a proc
- before action hook for %{name} is a %{class_name}, not a pro
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/372675f69c291adc.
Report an issue: GitHub.