{"record":{"id":"2acc4a756b9366f9","repo":"puppetlabs/puppet","slug":"after-action-hook-for-name-is-a-class-name","errorCode":null,"errorMessage":"after action hook for %{name} is a %{class_name}, not a proc","messagePattern":"after action hook for %(.+?) is a %(.+?), not a proc","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/interface/option.rb","lineNumber":170,"sourceCode":"\n  attr_reader :before_action\n\n  def before_action=(proc)\n    unless proc.is_a? Proc\n      # TRANSLATORS 'proc' is a Ruby block of code\n      raise ArgumentError, _(\"before action hook for %{name} is a %{class_name}, not a proc\") %\n                           { name: self, class_name: proc.class.name.inspect }\n    end\n    @before_action =\n      @parent.__send__(:__add_method, __decoration_name(:before), proc)\n  end\n\n  attr_reader :after_action\n\n  def after_action=(proc)\n    unless proc.is_a? Proc\n      # TRANSLATORS 'proc' is a Ruby block of code\n      raise ArgumentError, _(\"after action hook for %{name} is a %{class_name}, not a proc\") %\n                           { name: self, class_name: proc.class.name.inspect }\n    end\n    @after_action =\n      @parent.__send__(:__add_method, __decoration_name(:after), proc)\n  end\n\n  def __decoration_name(type)\n    if @parent.is_a? Puppet::Interface::Action then\n      :\"option #{name} from #{parent.name} #{type} decoration\"\n    else\n      :\"option #{name} #{type} decoration\"\n    end\n  end\nend\n","sourceCodeStart":152,"sourceCodeEnd":185,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/interface/option.rb#L152-L185","documentation":"Puppet::Interface::Option#after_action= registers a post-action hook the same way before_action does and equally requires a Proc (lib/puppet/interface/option.rb:170). Anything non-callable (Symbol, Method, String) is rejected because the hook is later invoked with `call`. Use the DSL `after_action { |action, args, options| ... }` to get the block handling for free.","triggerScenarios":"`opt.after_action = :log_result` (Symbol); `opt.after_action = method(:log_result)` (Method, not a Proc); assigning a hook variable that holds nil or a name string.","commonSituations":"Adding cleanup/teardown hooks by name; refactoring face code into helper methods and assigning references instead of wrappers.","solutions":["Pass a wrapping proc: `opt.after_action = proc { |action, args, options| log_result(options) }`","Convert Method objects with `.to_proc`","Prefer the DSL `after_action` inside the option block"],"exampleFix":"# before\nopt.after_action = :log_result\n\n# after\nopt.after_action = proc { |action, args, options| log_result(options) }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def hook!(value, what)\n  raise ArgumentError, \"#{what} must be a Proc\" unless value.is_a?(Proc)\n  value\nend\n\nopt.after_action = hook!(candidate, 'after_action')","tryCatchPattern":null,"preventionTips":["Register post-hooks with the DSL `after_action { |action, args, options| ... }`","Convert Method objects with `.to_proc` before assignment","Assert Proc-ness in test fixtures that exercise hook registration"],"tags":["puppet","faces","dsl","proc","argumenterror"],"backgroundTag":"wrong-argument-type","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}