{"record":{"id":"d0440b9d2c22a022","repo":"puppetlabs/puppet","slug":"libraries-must-be-passed-as-strings-not-klass","errorCode":null,"errorMessage":"Libraries must be passed as strings not %{klass}","messagePattern":"Libraries must be passed as strings not %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/feature.rb","lineNumber":110,"sourceCode":"        result = nil\n      end\n      @results[name] = result\n      result\n    else\n      libs = options[:libs]\n      if libs\n        libs = [libs] unless libs.is_a?(Array)\n        libs.all? { |lib| load_library(lib, name) } ? true : nil\n      else\n        true\n      end\n    end\n  end\n\n  private\n\n  def load_library(lib, name)\n    raise ArgumentError, _(\"Libraries must be passed as strings not %{klass}\") % { klass: lib.class } unless lib.is_a?(String)\n\n    @rubygems ||= Puppet::Util::RubyGems::Source.new\n    @rubygems.clear_paths\n\n    begin\n      require lib\n      true\n    rescue LoadError\n      # Expected case. Required library insn't installed.\n      debug_once(_(\"Could not find library '%{lib}' required to enable feature '%{name}'\") %\n        { lib: lib, name: name })\n      false\n    rescue StandardError, ScriptError => detail\n      debug_once(_(\"Exception occurred while loading library '%{lib}' required to enable feature '%{name}': %{detail}\") %\n        { lib: lib, name: name, detail: detail })\n      false\n    end\n  end","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/feature.rb#L92-L128","documentation":"Puppet::Util::Feature#add declares an optional capability and tests it by require-ing each library listed in :libs. load_library enforces that every entry is a String (it is passed straight to Kernel#require); a Symbol or any other class raises ArgumentError naming the offending class. The feature test never runs when this fires.","triggerScenarios":"Calling Puppet.features.add(:my_feature, libs: [:my_lib]) or libs: :my_lib — symbols instead of strings — or passing constants/objects in the libs array. Only strings are require-able, so anything else is rejected up front.","commonSituations":"Custom extensions and modules registering features using symbol lists (a natural style slip in Puppet code, where so many APIs take symbols), and code migrated from older examples with different conventions.","solutions":["Pass the libraries as strings: libs: %w[selinux] or libs: ['selinux']","Coerce defensively when the list comes from config: Array(libs).map(&:to_s)","For a single library a bare string is fine; Feature#add wraps non-Array values in an array automatically"],"exampleFix":"# before\nPuppet.features.add(:my_feature, libs: [:my_lib])\n# => ArgumentError: Libraries must be passed as strings not Symbol\n\n# after\nPuppet.features.add(:my_feature, libs: %w[my_lib])","handlingStrategy":"type-guard","validationCode":"libs = Array(raw_libs).map { |lib| lib.is_a?(String) ? lib : lib.to_s }\nPuppet.features.add(:my_feature, libs: libs)","typeGuard":"def string_libs?(libs)\n  Array(libs).all? { |lib| lib.is_a?(String) }\nend","tryCatchPattern":null,"preventionTips":["Always use %w[...] string arrays for :libs","Whitelist with an all?(String) predicate when the library list comes from config"],"tags":["ruby","argument-type","feature-detection","puppet"],"backgroundTag":"invalid-argument-type","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}