puppetlabs/puppet · error · ArgumentError

a data type can only have one implementation

Error message

a data type can only have one implementation

What it means

TypeBuilderAPI#implementation raises ArgumentError when has_implementation? is true — i.e. the type already has an implementation from an earlier `implementation { }` block or from `implementation_class`. A Puppet data type can carry exactly one implementation.

Source

Thrown at lib/puppet/datatypes.rb:203

    end
  end

  # The TypeBuilderAPI class exposes only those methods that the builder API provides
  # @api public
  class TypeBuilderAPI
    # @api private
    def initialize(type_builder)
      @type_builder = type_builder
    end

    def interface(type_string)
      raise ArgumentError, _('a data type can only have one interface') unless @type_builder.interface.nil?

      @type_builder.interface = type_string
    end

    def implementation(&block)
      raise ArgumentError, _('a data type can only have one implementation') if @type_builder.has_implementation?

      @type_builder.implementation = block
    end

    def implementation_class(ruby_class)
      raise ArgumentError, _('a data type can only have one implementation') if @type_builder.has_implementation?

      @type_builder.implementation_class = ruby_class
    end

    def load_file(file_name)
      Puppet::Util::Autoload.load_file(file_name, Puppet.lookup(:current_environment))
    end
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Keep exactly one implementation source: either one implementation block or one implementation_class, not both
  2. To share behavior, put helpers in a Ruby module and include it inside the single implementation block
  3. Merge the bodies of duplicate implementation blocks into one

Example fix

# before
Puppet::DataTypes.create_type('T') do
  interface 'attributes => {}'
  implementation_class AcmeImpl
  implementation { def extra; 1; end }
end
# after
Puppet::DataTypes.create_type('T') do
  interface 'attributes => {}'
  implementation_class AcmeImpl  # sole implementation
end
Defensive patterns

Strategy: validation

Validate before calling

src = File.read(path)
impl_calls = src.scan(/^\s*implementation(_class)?(\s|\{|\()/).size
raise "#{path}: expected exactly 1 implementation, found #{impl_calls}" unless impl_calls == 1

Prevention

When it happens

Trigger: Two `implementation { ... }` blocks in one create_type block; `implementation_class Foo` followed by `implementation { ... }` (or the reverse order).

Common situations: Copying behavior from another type by pasting its implementation block alongside an existing implementation_class; merging two data types by hand.

Related errors


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