{"record":{"id":"e246edf85dfbae78","repo":"puppetlabs/puppet","slug":"functions-must-be-based-on-puppet-pops-functions","errorCode":null,"errorMessage":"Functions must be based on Puppet::Pops::Functions::Function. Got %{function_base}","messagePattern":"Functions must be based on Puppet::Pops::Functions::Function\\. Got %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/functions.rb","lineNumber":213,"sourceCode":"    raise ArgumentError, _(\"Function Load Error for function '%{function_name}': %{message}\") % { function_name: func_name, message: e.message }\n  end\n\n  # Creates a function in, or in a local loader under the given loader.\n  # This method should only be used when manually creating functions\n  # for the sake of testing. Functions that are autoloaded should\n  # always use the `create_function` method and the autoloader will supply\n  # the correct loader.\n  #\n  # @param func_name [String, Symbol] a simple or qualified function name\n  # @param loader [Puppet::Pops::Loaders::Loader] the loader loading the function\n  # @param block [Proc] the block that defines the methods and dispatch of the\n  #   Function to create\n  # @return [Class<Function>] the newly created Function class\n  #\n  # @api public\n  def self.create_loaded_function(func_name, loader, function_base = Function, &block)\n    if function_base.ancestors.none? { |s| s == Puppet::Pops::Functions::Function }\n      raise ArgumentError, _(\"Functions must be based on Puppet::Pops::Functions::Function. Got %{function_base}\") % { function_base: function_base }\n    end\n\n    func_name = func_name.to_s\n    # Creates an anonymous class to represent the function\n    # The idea being that it is garbage collected when there are no more\n    # references to it.\n    #\n    # (Do not give the class the block here, as instance variables should be set first)\n    the_class = Class.new(function_base)\n\n    unless loader.nil?\n      the_class.instance_variable_set(:'@loader', loader.private_loader)\n    end\n\n    # Make the anonymous class appear to have the class-name <func_name>\n    # Even if this class is not bound to such a symbol in a global ruby scope and\n    # must be resolved via the loader.\n    # This also overrides any attempt to define a name method in the given block","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/functions.rb#L195-L231","documentation":"create_loaded_function validates that the base class passed as function_base has Puppet::Pops::Functions::Function among its ancestors. Any class that skips that chain, or a Module passed instead of a Class, raises this ArgumentError at definition time. The base class is the second argument to Puppet::Functions.create_function.","triggerScenarios":"Puppet::Functions.create_function(:foo, MyCustomBase) where MyCustomBase does not derive from Puppet::Functions::Function (which itself derives from Puppet::Pops::Functions::Function). Also triggered by passing a Module used as a mixin, or a typo'd constant that resolves to an unrelated class.","commonSituations":"Authors adding shared behavior through a custom function base; refactors that reparent the base class; scaffolding copied between Puppet versions where the base hierarchy changed.","solutions":["Derive the custom base from Puppet::Functions::Function so the ancestor check passes.","If you only need shared helpers, drop the custom base and include ordinary Ruby modules inside the create_function block instead.","Confirm you passed a Class, not a Module, as the second argument."],"exampleFix":"# before: base class outside the Function hierarchy\nclass MyCoolBase; end\nPuppet::Functions.create_function(:f, MyCoolBase) { ... }\n\n# after: derive from Puppet::Functions::Function\nclass MyCoolBase < Puppet::Functions::Function; end\nPuppet::Functions.create_function(:f, MyCoolBase) { ... }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"# Guard the base class before calling create_function\ndef valid_function_base?(klass)\n  klass.is_a?(Class) && klass.ancestors.include?(Puppet::Pops::Functions::Function)\nend\n\nraise ArgumentError, 'bad base' unless valid_function_base?(MyCoolBase)","tryCatchPattern":null,"preventionTips":["Derive custom bases from Puppet::Functions::Function by habit.","Prefer mixins included inside the block over custom base classes.","Assert ancestors in the spec for any shared function base."],"tags":["puppet","functions","base-class","api-misuse"],"backgroundTag":"invalid-base-class","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}