puppetlabs/puppet · error · ArgumentError

Data Type Load Error for type '%{type_name}': %{message}

Error message

Data Type Load Error for type '%{type_name}': %{message}

What it means

Puppet::DataTypes.create_type wraps the entire Ruby data-type definition block: any StandardError raised while building the type (unparsable interface string, duplicate interface/implementation declarations, NameError inside the implementation, load_file of a missing file) is re-raised as ArgumentError 'Data Type Load Error for type X: <original message>'. The text after the colon is the underlying exception and identifies the true fault.

Source

Thrown at lib/puppet/datatypes.rb:135

#
#     # This load_file is optional and only needed in case
#     # the implementation is not loaded by other means.
#     load_file 'puppetx/auth/user'
#
#     implementation_class PuppetX::Auth::User
#   end
#
module Puppet::DataTypes
  def self.create_type(type_name, &block)
    # Ruby < 2.1.0 does not have method on Binding, can only do eval
    # and it will fail unless protected with an if defined? if the local
    # variable does not exist in the block's binder.
    #

    loader = block.binding.eval('loader_injected_arg if defined?(loader_injected_arg)')
    create_loaded_type(type_name, loader, &block)
  rescue StandardError => e
    raise ArgumentError, _("Data Type Load Error for type '%{type_name}': %{message}") % { type_name: type_name, message: e.message }
  end

  def self.create_loaded_type(type_name, loader, &block)
    builder = TypeBuilder.new(type_name.to_s)
    api = TypeBuilderAPI.new(builder).freeze
    api.instance_eval(&block)
    builder.create_type(loader)
  end

  # @api private
  class TypeBuilder
    attr_accessor :interface, :implementation, :implementation_class

    def initialize(type_name)
      @type_name = type_name
      @implementation = nil
      @implementation_class = nil
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Read the message after 'Data Type Load Error for type X: ' — it is the root-cause exception text; fix that first
  2. Sanity-check the interface string by parsing it: Puppet::Pops::Parser::EvaluatingParser.new.parse_string("{ #{iface} }")
  3. Reproduce in isolation: place the type in a scratch module and run `puppet apply -e 'notice(My::Type)'`

Example fix

# before
Puppet::DataTypes.create_type('Bad') { interface 'attributes => {' }  # unbalanced braces
# after
Puppet::DataTypes.create_type('Good') { interface 'attributes => { value => String }' }
Defensive patterns

Strategy: try-catch

Validate before calling

# fail fast with a clean message while loading type files
begin
  Puppet::DataTypes.create_type(name, &block)
rescue ArgumentError => e
  raise unless e.message =~ /Data Type Load Error/
  raise "#{name}: #{e.message}"
end

Try / catch

begin
  Puppet::DataTypes.create_type('My::Type', &block)
rescue ArgumentError => e
  if e.message.start_with?('Data Type Load Error')
    # the suffix is the original exception's message — log it, fix the type definition
    Puppet.err e.message
  else
    raise
  end
end

Prevention

When it happens

Trigger: Authoring Puppet::DataTypes.create_type('My::Type') { ... } in lib/puppet/datatypes with an interface string that fails to parse; declaring interface or implementation twice; the implementation block referencing an undefined constant; load_file pointing at a nonexistent file.

Common situations: First drafts of Ruby data types in a module; refactors that break the interface string; Puppet upgrades that made the parser stricter.

Related errors


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