puppetlabs/puppet · error · RuntimeError
Loading of #{name} using relative path: '#{loaded_path}' did
Error message
Loading of #{name} using relative path: '#{loaded_path}' did not create expected class What it means
When ClassLoader resolves a dotted name to a Ruby constant it first tries Object's namespace chain, then the Puppet autoloader. This RuntimeError means the autoloader reported a file as loaded, but the expected constant still does not exist after the load — the file on disk does not match the name being resolved.
Source
Thrown at lib/puppet/pops/types/class_loader.rb:96
def self.provide_from_string(name)
name_path = name.split(TypeFormatter::NAME_SEGMENT_SEPARATOR)
# always from the root, so remove an empty first segment
name_path.shift if name_path[0].empty?
provide_from_name_path(name, name_path)
end
def self.provide_from_name_path(name, name_path)
# If class is already loaded, try this first
result = find_class(name_path)
unless result.is_a?(Module)
# Attempt to load it using the auto loader
loaded_path = nil
if paths_for_name(name_path).find { |path| loaded_path = path; @autoloader.load(path, Puppet.lookup(:current_environment)) }
result = find_class(name_path)
unless result.is_a?(Module)
raise RuntimeError, "Loading of #{name} using relative path: '#{loaded_path}' did not create expected class"
end
end
end
return nil unless result.is_a?(Module)
result
end
private_class_method :provide_from_string
def self.find_class(name_path)
name_path.reduce(Object) do |ns, name|
ns.const_get(name, false) # don't search ancestors
rescue NameError
return nil
end
end
private_class_method :find_class
View on GitHub (pinned to e227c27540)
Solutions
- Make the file's constant nesting match the resolved name path exactly (module PuppetX; module MyModule; class Thing ... for PuppetX::MyModule::Thing).
- Check character casing of both the file name and every module/class segment against the requested name.
- Ensure the implementation file itself defines (or reopens) the constant — requiring another file that defines it elsewhere in the path is not enough if the namespace differs.
- Reproduce in a Ruby shell: require the file manually, then check Object.const_defined?('PuppetX::MyModule::Thing') to see what was actually defined.
Example fix
# before — lib/puppet_x/my_module/thing.rb
class Thing; end # defines ::Thing, not PuppetX::MyModule::Thing
# after
module PuppetX
module MyModule
class Thing; end
end
end Defensive patterns
Strategy: validation
Validate before calling
# Ruby — verify the constant exists after an explicit require, before relying on ClassLoader
path = 'puppet_x/mymod/thing'
require path
unless Object.const_defined?('PuppetX::MyMod::Thing', false)
raise LoadError, "#{path} loaded but PuppetX::MyMod::Thing is not defined — check nesting/casing"
end Type guard
def resolves_to_module?(name_path)
name_path.reduce(Object) do |ns, n|
return false unless ns.const_defined?(n, false)
ns.const_get(n, false)
end.is_a?(Module)
end Try / catch
begin
Puppet::Pops::Types::ClassLoader.provide(name)
rescue RuntimeError => e
# report file vs constant mismatch instead of failing opaquely
raise LoadError, "#{e.message} — verify the file defines #{name} with exact nesting and casing"
end Prevention
- Develop modules on a case-sensitive filesystem (Linux) so file/constant casing bugs surface early.
- Add a smoke test per module that requires each implementation file and asserts the constant is defined.
When it happens
Trigger: ClassLoader.provide / provide_from_name_path resolving a name whose autoload file exists (e.g. under lib/puppet_x/<module>/ or lib/puppet/...) and executes cleanly, but defines the constant in a different namespace, with different casing, or not at all (e.g. it only requires another file).
Common situations: File name vs constant casing mismatch that only fails on case-sensitive filesystems (Linux CI after passing on macOS/Windows); module renamed internally but not the file layout; an implementation file that delegates to another file instead of defining/reopening the constant; environment load-path changes that pick up a stale file.
Related errors
- Unable to load class #{class_name}
- Could not find class %{name} for %{node}
- The code loaded from %{source_ref} must contain only the pla
- The code loaded from %{source_ref} does not define the plan
- Only Runtime type 'ruby' is supported, got #{type.runtime}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/d1d42d771c736454.
Report an issue: GitHub.