{"record":{"id":"f4df144cefd30363","repo":"puppetlabs/puppet","slug":"attempt-to-redefine-implementation-override-for","errorCode":null,"errorMessage":"attempt to redefine implementation override for #{label}","messagePattern":"attempt to redefine implementation override for #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/p_object_type.rb","lineNumber":589,"sourceCode":"\n  # @api private\n  def implementation_class=(cls)\n    raise ArgumentError, \"attempt to redefine implementation class for #{label}\" unless @implementation_class.nil?\n\n    @implementation_class = cls\n  end\n\n  # The block passed to this method will be passed in a call to `#class_eval` on the dynamically generated\n  # class for this data type. It's indended use is to complement or redefine the generated methods and\n  # attribute readers.\n  #\n  # The method is normally called with the block passed to `#implementation` when a data type is defined using\n  # {Puppet::DataTypes::create_type}.\n  #\n  # @api private\n  def implementation_override=(block)\n    if !@implementation_class.nil? || instance_variable_defined?(:@implementation_override)\n      raise ArgumentError, \"attempt to redefine implementation override for #{label}\"\n    end\n\n    @implementation_override = block\n  end\n\n  def extract_init_hash(o)\n    return o._pcore_init_hash if o.respond_to?(:_pcore_init_hash)\n\n    result = {}\n    pic = parameter_info(o.class)\n    attrs = attributes(true)\n    pic[0].each do |name|\n      v = o.send(name)\n      result[name] = v unless attrs[name].default_value?(v)\n    end\n    result\n  end\n","sourceCodeStart":571,"sourceCodeEnd":607,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/p_object_type.rb#L571-L607","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Search the entire modulepath for files under lib/puppet/datatype/ and grep for create_type('<TypeName>') to find the duplicate definition; keep exactly one","If two distinct types collided, rename one of them (names must be unique per name authority)","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","If re-registration is intentional in a dev loop, rescue ArgumentError and reuse the already-registered type"],"exampleFix":"# before: two files both declare the same type\n#   module_a/lib/puppet/datatype/myapp/thing.rb\n#   module_b/lib/puppet/datatype/myapp/thing.rb\nPuppet::DataTypes.create_type('MyApp::Thing') do\n  interface <<-PUPPET\n    attributes => { value => String }\n  PUPPET\n  implementation { def extra; 42; end }\nend\n\n# after: delete one file so only a single definition remains\n# (grep first: grep -r \"create_type('MyApp::Thing')\" <modulepath>)","handlingStrategy":"try-catch","validationCode":"# CI check: fail the build when two datatype files declare the same type\nnames = Dir['**/lib/puppet/datatype/**/*.rb'].flat_map do |f|\n  File.readlines(f).grep(/create_type\\(['\"]([^'\"]+)['\"]/) { Regexp.last_match(1) }.map { |n| [n, f] }\nend\ndupes = names.group_by(&:first).select { |_, v| v.size > 1 }\nabort \"duplicate data type definitions: #{dupes.inspect}\" unless dupes.empty?","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::DataTypes.create_type('MyApp::Thing') { ... }\nrescue ArgumentError => e\n  raise unless e.message.include?('attempt to redefine implementation override')\n  # type already configured in this process; reuse it instead of redefining\n  Puppet::Pops::Types::TypeParser.singleton.parse('MyApp::Thing', loader)\nend","preventionTips":["Keep data type names unique across all modules on the modulepath","Never require or eval files under lib/puppet/datatype manually; let Puppet's loader do it exactly once","Add a CI grep for duplicate create_type calls before deploying environments","Avoid re-running create_type during hot reload; construct a fresh PObjectType instead"],"tags":["puppet","pcore","data-type","duplicate-definition","ruby"],"backgroundTag":"duplicate-type-definition","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}