{"record":{"id":"f3f558c287d0e957","repo":"puppetlabs/puppet","slug":"the-code-loaded-from-source-ref-did-not-produce-f3f558","errorCode":null,"errorMessage":"The code loaded from %{source_ref} did not produce a Function class when evaluated. Got '%{klass}'","messagePattern":"The code loaded from %(.+?) did not produce a Function class when evaluated\\. Got '%(.+?)'","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/loader/ruby_function_instantiator.rb","lineNumber":27,"sourceCode":"  #\n  # @param loader [Puppet::Pops::Loader::Loader] The loader the function is associated with\n  # @param typed_name [Puppet::Pops::Loader::TypedName] the type / name of the function to load\n  # @param source_ref [URI, String] a reference to the source / origin of the ruby code to evaluate\n  # @param ruby_code_string [String] ruby code in a string\n  #\n  # @return [Puppet::Pops::Functions.Function] - an instantiated function with global scope closure associated with the given loader\n  #\n  def self.create(loader, typed_name, source_ref, ruby_code_string)\n    unless ruby_code_string.is_a?(String) && ruby_code_string =~ /Puppet::Functions\\.create_function/\n      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 }\n    end\n\n    # make the private loader available in a binding to allow it to be passed on\n    loader_for_function = loader.private_loader\n    here = get_binding(loader_for_function)\n    created = eval(ruby_code_string, here, source_ref, 1) # rubocop:disable Security/Eval\n    unless created.is_a?(Class)\n      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 }\n    end\n    unless created.name.to_s == typed_name.name()\n      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 }\n    end\n\n    # create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things\n    # when calling functions etc.\n    # It should be bound to global scope\n\n    # Sets closure scope to nil, to let it be picked up at runtime from Puppet.lookup(:global_scope)\n    # If function definition used the loader from the binding to create a new loader, that loader wins\n    created.new(nil, loader_for_function)\n  end\n\n  # Produces a binding where the given loader is bound as a local variable (loader_injected_arg). This variable can be used in loaded\n  # ruby code - e.g. to call Puppet::Function.create_loaded_function(:name, loader,...)\n  #\n  def self.get_binding(loader_injected_arg)","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/loader/ruby_function_instantiator.rb#L9-L45","documentation":"Raised by RubyFunctionInstantiator when the Ruby source evals successfully but does not produce a Class. Puppet::Functions.create_function returns the generated anonymous function class; if the file's value is anything else (nil, String, object) this ArgumentError reports the actual class.","triggerScenarios":"`eval(...)` result fails `is_a?(Class)`: the last expression of the file is not the create_function call -- e.g. trailing statements after the definition block, or the call wrapped in a conditional leaving another expression as the file value.","commonSituations":"Appending logging/configuration after the create_function block; refactorings that change the file's final expression; editing generated functions and adding code at the bottom.","solutions":["Make Puppet::Functions.create_function(...) the final expression of the file","Use the 'Got' class from the message to find the trailing expression and move it above the definition"],"exampleFix":"# before\nPuppet::Functions.create_function(:'mymod::double') do ... end\nPuppet.info('loaded double')\n\n# after\nPuppet.info('loading double')\nPuppet::Functions.create_function(:'mymod::double') do ... end","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def function_class?(obj)\n  obj.is_a?(Class) && obj < Puppet::Pops::Functions::Function\nend","tryCatchPattern":"begin\n  fn = loader.load_typed(typed_name)\nrescue ArgumentError => e\n  raise unless e.message.include?('did not produce a Function class')\n  warn \"file does not evaluate to a function class: #{e.message}\"\nend","preventionTips":["Make create_function the last expression of every function file","Add statements above, never below, the definition","Smoke-load all functions in CI (call Puppet::Pal or the loader once per function)"],"tags":["puppet","function","ruby","loader","eval"],"backgroundTag":"puppet-function-load-validation","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}