puppetlabs/puppet · error · ArgumentError

Each entry for purge_ssh_keys must be a string, not a %{klas

Error message

Each entry for purge_ssh_keys must be a string, not a %{klass}

What it means

Raised by the validate block of the `purge_ssh_keys` property on the `user` type. After allowing the true/false symbols, the value (a bare String is wrapped into a one-element array) must be an Array whose every entry is_a?(String); any non-String entry (Integer, nil, hash) raises this with the entry's class interpolated. Each string entry is then also required to be an absolute path or start with ~/ or %h/ (see the companion path error).

Source

Thrown at lib/puppet/type/user.rb:743

        * An array of file paths --- look for keys in all of the files listed. Purge
          any keys that aren't managed as `ssh_authorized_key` resources. If any of
          these paths starts with `~` or `%h`, that token will be replaced with
          the user's home directory."

      defaultto :false

      # Use Symbols instead of booleans until PUP-1967 is resolved.
      newvalues(:true, :false)

      validate do |value|
        if [:true, :false].include? value.to_s.intern
          return
        end

        value = [value] if value.is_a?(String)
        if value.is_a?(Array)
          value.each do |entry|
            raise ArgumentError, _("Each entry for purge_ssh_keys must be a string, not a %{klass}") % { klass: entry.class } unless entry.is_a?(String)

            valid_home = Puppet::Util.absolute_path?(entry) || entry =~ %r{^~/|^%h/}
            raise ArgumentError, _("Paths to keyfiles must be absolute, not %{entry}") % { entry: entry } unless valid_home
          end
          return
        end
        raise ArgumentError, _("purge_ssh_keys must be true, false, or an array of file names, not %{value}") % { value: value.inspect }
      end

      munge do |value|
        # Resolve string, boolean and symbol forms of true and false to a
        # single representation.
        case value
        when :false, false, "false"
          []
        when :true, true, "true"
          home = homedir
          home ? ["#{home}/.ssh/authorized_keys"] : []

View on GitHub (pinned to e227c27540)

Solutions

  1. Ensure every entry is a string: `purge_ssh_keys => ['/etc/ssh/keys/alice/authorized_keys']`
  2. Quote numeric-looking path components in YAML/Hiera
  3. Map/clean the list in the profile: $keys.map |$k| { String($k) } before passing

Example fix

# before
user { 'alice':
  ensure          => present,
  purge_ssh_keys  => [12345],
}

# after
user { 'alice':
  ensure          => present,
  purge_ssh_keys  => ['/etc/ssh/keys/alice/authorized_keys'],
}
Defensive patterns

Strategy: validation

Validate before calling

keys = [raw].flatten.compact
raise TypeError, 'purge_ssh_keys entries must be strings' unless keys.all? { |k| k.is_a?(String) }
keys = keys.map(&:to_s) rescue nil

Type guard

def valid_purge_keys?(v)
  return true if [true, false].include?(v)
  v.is_a?(Array) && v.all? { |e| e.is_a?(String) }
end

Prevention

When it happens

Trigger: `user { 'alice': purge_ssh_keys => [12345] }`, `=> [nil]`, `=> [{'path' => 'x'}]`; Hiera data mixing types; YAML unquoted values parsed as integers (e.g. a path like 2024).

Common situations: YAML bare tokens that parse as numbers; lookup() results merged from heterogeneous sources; programmatic generation of key lists that includes integers or nils.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/235c14ce124928cb. Report an issue: GitHub.