puppetlabs/puppet · error · ArgumentError
%{option} already has an after_action set
Error message
%{option} already has an after_action set What it means
OptionBuilder#after_action permits a single hook per option; a second registration raises because `@option.after_action` is already set (lib/puppet/interface/option_builder.rb:72). Like its before_action twin, the DSL offers no chaining, so duplicates are rejected outright at definition time.
Source
Thrown at lib/puppet/interface/option_builder.rb:72
# 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
unless block.arity == 3 then
# TRANSLATORS 'after_action' is a method name and should not be translated
raise ArgumentError, _("after_action takes three arguments, action, args, and options")
end
@option.after_action = block
end
# Sets whether the option is required. If no argument is given it
# defaults to setting it as a required option.
# @api public
# @dsl Faces
def required(value = true)
@option.required = value
end
# Sets a block that will be used to compute the default value for thisView on GitHub (pinned to e227c27540)
Solutions
- Combine both bodies into one `after_action` block
- Remove the leftover hook after refactoring
- Split distinct concerns across before_action and after_action where timing allows
Example fix
# before
option "--foo" do
after_action { |a, args, opts| log(opts) }
after_action { |a, args, opts| cleanup(opts) }
end
# after
option "--foo" do
after_action do |a, args, opts|
log(opts)
cleanup(opts)
end
end Defensive patterns
Strategy: validation
Validate before calling
# before registering on an Option object
raise ArgumentError, 'after_action already set' if opt.after_action
opt.after_action = proc { |action, args, options| cleanup(options) } Prevention
- One after_action per option; fold extra work into the single block
- Review copy-pasted option blocks for duplicated hooks
- When concerns differ in timing, split across before_action/after_action rather than stacking
When it happens
Trigger: Two `after_action` blocks in one option block; a shared helper called twice that registers the hook each time.
Common situations: Adding logging and cleanup separately instead of together; merging code where both halves kept their own after_action.
Related errors
- %{option} already has a before_action set
- %{option} already has a default value
- %{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/d1067f0b36acce60.
Report an issue: GitHub.