{"record":{"id":"ceec84cee730f0c3","repo":"puppetlabs/puppet","slug":"title-or-name-must-be-provided","errorCode":null,"errorMessage":"Title or name must be provided","messagePattern":"Title or name must be provided","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/type.rb","lineNumber":1207,"sourceCode":"\n      sources << provider.source\n      provider\n    end\n  end\n\n  # Converts a simple hash into a Resource instance.\n  # @todo as opposed to a complex hash? Other raised exceptions?\n  # @param [Hash{Symbol, String => Object}] hash resource attribute to value map to initialize the created resource from\n  # @return [Puppet::Resource] the resource created from the hash\n  # @raise [Puppet::Error] if a title is missing in the given hash\n  def self.hash2resource(hash)\n    hash = hash.each_with_object({}) { |ary, result| result[ary[0].to_sym] = ary[1]; }\n\n    title = hash.delete(:title)\n    title ||= hash[:name]\n    title ||= hash[key_attributes.first] if key_attributes.length == 1\n\n    raise Puppet::Error, \"Title or name must be provided\" unless title\n\n    # Now create our resource.\n    resource = Puppet::Resource.new(self, title)\n    resource.catalog = hash.delete(:catalog)\n\n    sensitive = hash.delete(:sensitive_parameters)\n    if sensitive\n      resource.sensitive_parameters = sensitive\n    end\n\n    hash.each do |param, value|\n      resource[param] = value\n    end\n    resource\n  end\n\n  # Returns an array of strings representing the containment hierarchy\n  # (types/classes) that make up the path to the resource from the root","sourceCodeStart":1189,"sourceCodeEnd":1225,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/type.rb#L1189-L1225","documentation":"Puppet::Type.hash2resource converts a plain attribute Hash into a Puppet::Resource (called from Puppet::Type#initialize at lib/puppet/type.rb:2316 whenever a Hash is passed instead of a Resource). It requires a title: the :title entry, else :name, else the type's single key attribute. If none is present, Puppet::Error 'Title or name must be provided' is raised before any attribute validation runs.","triggerScenarios":"Puppet::Type.type(:file).new(ensure: :present) — a hash with no :name/:title; hashes built programmatically where the name key was deleted or never set; :name present but explicitly nil (the check is truthiness, not key presence); a type with multiple key_attributes and only a title-less hash supplied.","commonSituations":"Bolt apply blocks or rspec-puppet helpers constructing resources from data hashes; tools converting hiera data into resources where the name key is optional and missing; refactors renaming :name to :path for file-like types without adding a title.","solutions":["Include :name (or :title) in the hash: Puppet::Type.type(:file).new(name: '/tmp/x', ensure: :present)","When building hashes from data, default the name explicitly and fail loudly if the source key is absent","For title-only resources (e.g., exec), pass title: 'my command' or set the namevar"],"exampleFix":"# before\nPuppet::Type.type(:exec).new(command: '/bin/true') # => Puppet::Error\n\n# after\nPuppet::Type.type(:exec).new(title: 'run-true', command: '/bin/true')","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'hash must include :title or :name' unless hash[:title] || hash[:name] || hash[self.key_attributes.first]","typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Type.type(:file).new(attrs)\nrescue Puppet::Error => e\n  raise unless e.message =~ /Title or name/\n  attrs = attrs.merge(name: attrs.fetch(:path, 'default'))\n  retry\nend","preventionTips":["Always set :name (or :title) when building resource hashes programmatically","Treat a nil :name as missing — the check is truthiness, not key presence","Validate data-to-resource converters with a schema (dry-validation) upstream"],"tags":["puppet","resource-creation","missing-namevar","title"],"backgroundTag":"missing-required-field","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}