puppetlabs/puppet · error · ArgumentError

attempt to redefine implementation override for #{label}

Error message

attempt to redefine implementation override for #{label}

What it means

Puppet data types defined with Puppet::DataTypes.create_type may carry an implementation block that is later class_eval'd into the generated implementation class (set via implementation_override= in lib/puppet/datatypes.rb:178). The setter is one-shot: it raises ArgumentError if the PObjectType already has an implementation class or an override block. In practice this means the same data type was defined twice in one process, each time with an implementation block.

Source

Thrown at lib/puppet/pops/types/p_object_type.rb:589

  # @api private
  def implementation_class=(cls)
    raise ArgumentError, "attempt to redefine implementation class for #{label}" unless @implementation_class.nil?

    @implementation_class = cls
  end

  # The block passed to this method will be passed in a call to `#class_eval` on the dynamically generated
  # class for this data type. It's indended use is to complement or redefine the generated methods and
  # attribute readers.
  #
  # The method is normally called with the block passed to `#implementation` when a data type is defined using
  # {Puppet::DataTypes::create_type}.
  #
  # @api private
  def implementation_override=(block)
    if !@implementation_class.nil? || instance_variable_defined?(:@implementation_override)
      raise ArgumentError, "attempt to redefine implementation override for #{label}"
    end

    @implementation_override = block
  end

  def extract_init_hash(o)
    return o._pcore_init_hash if o.respond_to?(:_pcore_init_hash)

    result = {}
    pic = parameter_info(o.class)
    attrs = attributes(true)
    pic[0].each do |name|
      v = o.send(name)
      result[name] = v unless attrs[name].default_value?(v)
    end
    result
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Search the entire modulepath for files under lib/puppet/datatype/ and grep for create_type('<TypeName>') to find the duplicate definition; keep exactly one
  2. If two distinct types collided, rename one of them (names must be unique per name authority)
  3. Do not eval or require the datatype file manually; let Puppet's loader load it once, and never re-run create_type on reload - build a new PObjectType instead
  4. If re-registration is intentional in a dev loop, rescue ArgumentError and reuse the already-registered type

Example fix

# before: two files both declare the same type
#   module_a/lib/puppet/datatype/myapp/thing.rb
#   module_b/lib/puppet/datatype/myapp/thing.rb
Puppet::DataTypes.create_type('MyApp::Thing') do
  interface <<-PUPPET
    attributes => { value => String }
  PUPPET
  implementation { def extra; 42; end }
end

# after: delete one file so only a single definition remains
# (grep first: grep -r "create_type('MyApp::Thing')" <modulepath>)
Defensive patterns

Strategy: try-catch

Validate before calling

# CI check: fail the build when two datatype files declare the same type
names = Dir['**/lib/puppet/datatype/**/*.rb'].flat_map do |f|
  File.readlines(f).grep(/create_type\(['"]([^'"]+)['"]/) { Regexp.last_match(1) }.map { |n| [n, f] }
end
dupes = names.group_by(&:first).select { |_, v| v.size > 1 }
abort "duplicate data type definitions: #{dupes.inspect}" unless dupes.empty?

Try / catch

begin
  Puppet::DataTypes.create_type('MyApp::Thing') { ... }
rescue ArgumentError => e
  raise unless e.message.include?('attempt to redefine implementation override')
  # type already configured in this process; reuse it instead of redefining
  Puppet::Pops::Types::TypeParser.singleton.parse('MyApp::Thing', loader)
end

Prevention

When it happens

Trigger: Calling Puppet::DataTypes.create_type('Some::Type') { ... implementation { ... } } twice in the same Ruby process: duplicate datatype files under two lib/puppet/datatype/ directories on the modulepath, the same file loaded by both environment setup and catalog compilation, or two modules declaring the same type name.

Common situations: Two modules shipping a data type with the same name; a data type defined at both environment level and module level; code reloaders (r10k, Code Manager, custom boot hooks) evaluating datatype files twice; agent and master running different code versions that both define a type.

Related errors


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