puppetlabs/puppet · error · ArgumentError

The code loaded from %{source_ref} produced mis-matched name

Error message

The code loaded from %{source_ref} produced mis-matched name, expected '%{type_name}', got %{created_name}

What it means

Raised by RubyFunctionInstantiator when the class produced by eval has a name different from the typed name. The symbol passed to Puppet::Functions.create_function must exactly match (case-sensitive == on to_s) the function name the loader binds, which is derived from the module layout and file path (e.g. mymod::double in lib/puppet/functions/mymod/double.rb).

Source

Thrown at lib/puppet/pops/loader/ruby_function_instantiator.rb:30

  # @param source_ref [URI, String] a reference to the source / origin of the ruby code to evaluate
  # @param ruby_code_string [String] ruby code in a string
  #
  # @return [Puppet::Pops::Functions.Function] - an instantiated function with global scope closure associated with the given loader
  #
  def self.create(loader, typed_name, source_ref, ruby_code_string)
    unless ruby_code_string.is_a?(String) && ruby_code_string =~ /Puppet::Functions\.create_function/
      raise ArgumentError, _("The code loaded from %{source_ref} does not seem to be a Puppet 4x API function - no create_function call.") % { source_ref: source_ref }
    end

    # make the private loader available in a binding to allow it to be passed on
    loader_for_function = loader.private_loader
    here = get_binding(loader_for_function)
    created = eval(ruby_code_string, here, source_ref, 1) # rubocop:disable Security/Eval
    unless created.is_a?(Class)
      raise ArgumentError, _("The code loaded from %{source_ref} did not produce a Function class when evaluated. Got '%{klass}'") % { source_ref: source_ref, klass: created.class }
    end
    unless created.name.to_s == typed_name.name()
      raise ArgumentError, _("The code loaded from %{source_ref} produced mis-matched name, expected '%{type_name}', got %{created_name}") % { source_ref: source_ref, type_name: typed_name.name, created_name: created.name }
    end

    # create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things
    # when calling functions etc.
    # It should be bound to global scope

    # Sets closure scope to nil, to let it be picked up at runtime from Puppet.lookup(:global_scope)
    # If function definition used the loader from the binding to create a new loader, that loader wins
    created.new(nil, loader_for_function)
  end

  # Produces a binding where the given loader is bound as a local variable (loader_injected_arg). This variable can be used in loaded
  # ruby code - e.g. to call Puppet::Function.create_loaded_function(:name, loader,...)
  #
  def self.get_binding(loader_injected_arg)
    binding
  end
  private_class_method :get_binding

View on GitHub (pinned to e227c27540)

Solutions

  1. Match the create_function symbol exactly to the namespaced name derived from the file path
  2. Rename the file or the symbol so both agree
  3. Remember this check is case-sensitive, unlike the data-type instantiator's casecmp

Example fix

# before - lib/puppet/functions/mymod/double.rb
Puppet::Functions.create_function(:'mymod::twice') do ... end

# after
Puppet::Functions.create_function(:'mymod::double') do ... end
Defensive patterns

Strategy: try-catch

Validate before calling

m = ruby_source.match(/Puppet::Functions\.create_function\(\s*:?'([^']+)'|Puppet::Functions\.create_function\(\s*:?"([^"]+)"/)
expected = namespaced_name_from_path(path)
warn "name mismatch: file says #{m && (m[1] || m[2])}, path says #{expected}" if m && (m[1] || m[2]) != expected

Try / catch

begin
  fn = loader.load_typed(typed_name)
rescue ArgumentError => e
  raise unless e.message.include?('mis-matched name')
  warn "function name mismatch: #{e.message}"
end

Prevention

When it happens

Trigger: `created.name.to_s != typed_name.name`: e.g. create_function(:'mymod::foo') in a file loaded as mymod::bar, or a missing module namespace segment (defining :double where :mymod::double is expected).

Common situations: Renaming a function in code but not the file (or vice versa); omitting the module namespace during 3x-to-4x migration; copy-pasted functions with stale names.

Related errors


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