puppetlabs/puppet · error · ArgumentError

Attempt to redefine method %{method} with block

Error message

Attempt to redefine method %{method} with block

What it means

newvalue(:name, :method => :sym, &block) optionally defines an instance method :sym on the property class, implemented by the given block; without a block :sym is aliased to call_provider. Puppet refuses to overwrite an already-defined instance method with a block (ArgumentError 'Attempt to redefine method') because silent replacement would hide bugs. Puppet::Property::Ensure itself defines :create and :destroy this way, so those names are classic collisions.

Source

Thrown at lib/puppet/property.rb:172

  #   to use?
  # @option options [Symbol] :invalidate_refreshes Indicates a change on this property should invalidate and
  #   remove any scheduled refreshes (from notify or subscribe) targeted at the same resource. For example, if
  #   a change in this property takes into account any changes that a scheduled refresh would have performed,
  #   then the scheduled refresh would be deleted.
  # @option options [Object] any Any other option is treated as a call to a setter having the given
  #   option name (e.g. `:required_features` calls `required_features=` with the option's value as an
  #   argument).
  #
  # @dsl type
  # @api public
  def self.newvalue(name, options = {}, &block)
    value = value_collection.newvalue(name, options, &block)

    unless value.method.nil?
      method = value.method.to_sym
      if value.block
        if instance_methods(false).include?(method)
          raise ArgumentError, _("Attempt to redefine method %{method} with block") % { method: method }
        end

        define_method(method, &value.block)
      else
        # Let the method be an alias for calling the providers setter unless we already have this method
        alias_method(method, :call_provider) unless method_defined?(method)
      end
    end
    value
  end

  # Calls the provider setter method for this property with the given value as argument.
  # @return [Object] what the provider returns when calling a setter for this property's name
  # @raise [Puppet::Error] when the provider can not handle this property.
  # @see #set
  # @api private
  #
  def call_provider(value)

View on GitHub (pinned to e227c27540)

Solutions

  1. Pick a method name that is not already defined (e.g. :make_present instead of :create).
  2. Drop the :method option so the value aliases to call_provider, and implement the behavior provider-side instead.
  3. Drop the block and define the method yourself (define_method) where you control collisions explicitly.

Example fix

# before (custom type)
newvalue(:present, :method => :create) do
  provider.create      # ArgumentError: 'create' already defined by Puppet::Property::Ensure
end

# after
newvalue(:present, :method => :make_present) do
  provider.create
end
Defensive patterns

Strategy: validation

Validate before calling

method_sym = :make_present
raise ArgumentError, "method :#{method_sym} already defined" if instance_methods(false).include?(method_sym)
newvalue(:present, :method => method_sym) { provider.create }

Type guard

def free_value_method?(klass, sym)
  !klass.instance_methods(false).include?(sym) && !klass.method_defined?(sym)
end

Prevention

When it happens

Trigger: A property declares newvalue(:present, :method => :create) { ... } while :create already exists - inherited from Property::Ensure or defined earlier in the same class; the same value is registered twice, the second time with :method pointing at a method the first registration created.

Common situations: Custom ensure-like properties copying the ensure idiom; module upgrades that add methods colliding with existing newvalue methods; inheriting from core property classes.

Related errors


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