{"record":{"id":"443a8fec0309e2e6","repo":"puppetlabs/puppet","slug":"class-name-must-be-provided","errorCode":null,"errorMessage":"Class name must be provided.","messagePattern":"Class name must be provided\\.","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/type/user.rb","lineNumber":798,"sourceCode":"        return entry unless entry.match?(%r{^(?:~|%h)/})\n\n        # if user doesn't exist (yet), ignore nonexistent homedir\n        home = homedir\n        return nil unless home\n\n        # compiler freezes \"value\" so duplicate using a gsub, second mutating gsub! is then ok\n        entry = entry.gsub(%r{^~/}, \"#{home}/\")\n        entry.gsub!(%r{^%h/}, \"#{home}/\")\n        entry\n      end\n    end\n\n    newproperty(:loginclass, :required_features => :manages_loginclass) do\n      desc \"The name of login class to which the user belongs.\"\n\n      validate do |value|\n        if value =~ /^\\d+$/\n          raise ArgumentError, _(\"Class name must be provided.\")\n        end\n      end\n    end\n\n    # Generate ssh_authorized_keys resources for purging. The key files are\n    # taken from the purge_ssh_keys parameter. The generated resources inherit\n    # all metaparameters from the parent user resource.\n    #\n    # @return [Array<Puppet::Type::Ssh_authorized_key] a list of resources\n    #   representing the found keys\n    # @see generate\n    # @api private\n    def find_unmanaged_keys\n      self[:purge_ssh_keys]\n        .select { |f| File.readable?(f) }\n        .map { |f| unknown_keys_in_file(f) }\n        .flatten.each do |res|\n          res[:ensure] = :absent","sourceCodeStart":780,"sourceCodeEnd":816,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/type/user.rb#L780-L816","documentation":"Raised by the validate block of the `loginclass` property (:required_features => :manages_loginclass, provided by the OpenBSD user provider) on the `user` type. Login classes (login.conf(5)) are names like 'staff' or 'daemon'; a value matching /^\\d+$/ is rejected as a numeric non-name. Note the message is generic ('Class name must be provided.') — it fires only for all-digit values, not for empty strings.","triggerScenarios":"`user { 'alice': loginclass => '0' }` on OpenBSD; numeric login.conf stanza identifiers from generated data; defaults copied from a spreadsheet's numeric class column.","commonSituations":"Automated manifests built from tabular data; misunderstanding loginclass as a class ID rather than a login.conf name; only relevant on OpenBSD since only its provider declares manages_loginclass.","solutions":["Pass the login.conf class name: `loginclass => 'staff'`","Verify valid names in /etc/login.conf on the target host","Remove numeric values from the source data"],"exampleFix":"# before\nuser { 'alice':\n  ensure      => present,\n  loginclass  => '0',\n}\n\n# after\nuser { 'alice':\n  ensure      => present,\n  loginclass  => 'staff',\n}","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'loginclass must be a login.conf name' if loginclass.to_s.match?(/\\A\\d+\\z/)","typeGuard":"def loginclass_name?(v)\n  v.is_a?(String) && !v.match?(/\\A\\d+\\z/)\nend","tryCatchPattern":null,"preventionTips":["Use names defined in /etc/login.conf ('staff', 'daemon', 'default')","Only set loginclass on OpenBSD — other providers lack manages_loginclass","Lint generated manifests for numeric loginclass values"],"tags":["puppet","user-resource","openbsd","loginclass","argument-validation"],"backgroundTag":"numeric-id-instead-of-name","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}