puppetlabs/puppet · error · ArgumentError
attempt to redefine implementation class for #{label}
Error message
attempt to redefine implementation class for #{label} What it means
PObjectType#implementation_class= may be assigned exactly once; a second assignment raises ArgumentError with the type's label. The one-shot setter prevents silently swapping the Ruby class behind a live data type after instances or generated methods already exist.
Source
Thrown at lib/puppet/pops/types/p_object_type.rb:574
# Use generator to create a default implementation
@implementation_class = RubyGenerator.new.create_class(self)
@implementation_class.class_eval(&@implementation_override) if instance_variable_defined?(:@implementation_override)
else
# Can the mapping be loaded?
@implementation_class = ClassLoader.provide(class_name)
raise Puppet::Error, "Unable to load class #{class_name}" if @implementation_class.nil?
unless @implementation_class < PuppetObject || @implementation_class.respond_to?(:ecore)
raise Puppet::Error, "Unable to create an instance of #{name}. #{class_name} does not include module #{PuppetObject.name}"
end
end
end
@implementation_class
end
# @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 = blockView on GitHub (pinned to e227c27540)
Solutions
- Define each data type name exactly once across all loaded modules; rename colliding types.
- Guard the assignment: `type.implementation_class = cls if type.implementation_class.nil?` in code that may run twice.
- In long-lived custom hosts, memoize type registration so files are processed once per process.
Example fix
# before type.implementation_class = cls # raises if already assigned # after type.implementation_class = cls if type.implementation_class.nil?
Defensive patterns
Strategy: validation
Validate before calling
# Ruby — make registration idempotent type.implementation_class = cls if type.implementation_class.nil?
Type guard
def implementation_assignable?(type) type.implementation_class.nil? end
Try / catch
begin type.implementation_class = cls rescue ArgumentError => e raise unless type.implementation_class == cls # tolerate benign re-registration of the same class end
Prevention
- Give every data type a unique name across all modules in the environment.
- In tests/long-lived processes, load type definition files once and memoize; never re-run create_type per request.
When it happens
Trigger: Ruby code calling type.implementation_class = cls when an implementation is already set — most commonly Puppet::DataTypes.create_type executed twice for the same type name in one process (two modules declaring the same data type, or test suites that load type definitions repeatedly), or custom registration code running on every request.
Common situations: Duplicate data type definitions with the same name across modules; rspec/task runs that re-evaluate type files without process isolation; frameworks that re-register types on reload without tracking what was already loaded.
Related errors
- #{label} has no value
- Unable to load class #{class_name}
- Unable to create an instance of #{name}. #{class_name} does
- Illegal format '#{actual}' specified for value of Object typ
- #{subject} #{what},
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/dd4e6d1c17fafc1c.
Report an issue: GitHub.