puppetlabs/puppet · error · Puppet::ParseError

Unable to find loader named '%{loader_name}'

Error message

Unable to find loader named '%{loader_name}'

What it means

Loaders#[] resolves a loader by its unique name; the lookup table is @loaders_by_name, populated from the modules and environment actually loaded. If the name is missing, it retries for module-private loaders by stripping a trailing ' private' suffix and asking private_loader_for_module; only if that also fails does it raise Puppet::ParseError. In practice the name comes from a module, so this error means 'the module behind this loader name is not loaded/known to this environment'.

Source

Thrown at lib/puppet/pops/loaders.rb:199

  # @api private
  def self.loaders
    loaders = Puppet.lookup(:loaders) { nil }
    raise Puppet::ParseError, _("Internal Error: Puppet Context ':loaders' missing") if loaders.nil?

    loaders
  end

  # Lookup a loader by its unique name.
  #
  # @param [String] loader_name the name of the loader to lookup
  # @return [Loader] the found loader
  # @raise [Puppet::ParserError] if no loader is found
  def [](loader_name)
    loader = @loaders_by_name[loader_name]
    if loader.nil?
      # Unable to find the module private loader. Try resolving the module
      loader = private_loader_for_module(loader_name[0..-9]) if loader_name.end_with?(' private')
      raise Puppet::ParseError, _("Unable to find loader named '%{loader_name}'") % { loader_name: loader_name } if loader.nil?
    end
    loader
  end

  # Finds the appropriate loader for the given `module_name`, or for the environment in case `module_name`
  # is `nil` or empty.
  #
  # @param module_name [String,nil] the name of the module
  # @return [Loader::Loader] the found loader
  # @raise [Puppet::ParseError] if no loader can be found
  # @api private
  def find_loader(module_name)
    if module_name.nil? || EMPTY_STRING == module_name
      # Use the public environment loader
      public_environment_loader
    else
      # TODO : Later check if definition is private, and then add it to private_loader_for_module
      #

View on GitHub (pinned to e227c27540)

Solutions

  1. Verify the module exists under the environment's modulepath and has valid metadata (metadata.json).
  2. Check the exact spelling of the name passed to [] — for private loaders it must be '<module> private' with the space, and the module segment must match a loaded module.
  3. Regenerate/re-upload artifacts that embed the stale loader name (e.g. re-compile plans after renaming a module).
  4. Run `puppet module list --environment <env>` (or equivalent) to see which module loaders were actually created.
Defensive patterns

Strategy: validation

Validate before calling

# Verify a loader name will resolve before using it
loaders = Puppet.lookup(:loaders)
module_name = loader_name.sub(/ private\z/, '')
env = loaders.environment
unless env.modules.any? { |m| m.name == module_name }
  raise ArgumentError, "module '#{module_name}' is not in the modulepath of environment '#{env.name}'"
end
loader = loaders[loader_name]

Try / catch

begin
  loader = Puppet.lookup(:loaders)[name]
rescue Puppet::ParseError => e
  # name is stale (module removed/renamed) — regenerate artifacts referencing it
  logger.warn("stale loader reference #{name}: #{e.message}")
  fallback_loader = Puppet.lookup(:loaders).environment_loader
end

Prevention

When it happens

Trigger: Calling Puppet.lookup(:loaders)['mymodule private'] (or any loader name) when 'mymodule' is absent from the modulepath; code or serialized plan/deferred metadata referencing a module that was removed or renamed; a typo in the module name portion of the loader name.

Common situations: Module removed or renamed between control-repo revisions while cached artifacts (compiled plans, deferred values, reports) still reference it; modulepath misconfiguration so Puppet never loaded the module; environment isolation differences between nodes.

Related errors


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