puppetlabs/puppet · error · ArgumentError
Command must be a String or Array<String>, got value of clas
Error message
Command must be a String or Array<String>, got value of class %{klass} What it means
The exec type's command parameter validates that its value is a String or an Array (of strings for parameterized invocation). Any other class — most commonly nil from an undef variable, or a Hash — raises ArgumentError 'Command must be a String or Array<String>'. This happens at resource validation time, before any execution attempt.
Source
Thrown at lib/puppet/type/exec.rb:218
succeeds, any output produced will be logged at the instance's
normal log level (usually `notice`), but if the command fails
(meaning its return code does not match the specified code) then
any output is logged at the `err` log level.
Multiple `exec` resources can use the same `command` value; Puppet
only uses the resource title to ensure `exec`s are unique.
On *nix platforms, the command can be specified as an array of
strings and Puppet will invoke it using the more secure method of
parameterized system calls. For example, rather than executing the
malicious injected code, this command will echo it out:
command => ['/bin/echo', 'hello world; rm -rf /']
"
validate do |command|
unless command.is_a?(String) || command.is_a?(Array)
raise ArgumentError, _("Command must be a String or Array<String>, got value of class %{klass}") % { klass: command.class }
end
end
end
newparam(:path) do
desc "The search path used for command execution.
Commands must be fully qualified if no path is specified. Paths
can be specified as an array or as a '#{File::PATH_SEPARATOR}' separated list."
# Support both arrays and colon-separated fields.
def value=(*values)
@value = values.flatten.collect { |val|
val.split(File::PATH_SEPARATOR)
}.flatten
end
end
newparam(:user) doView on GitHub (pinned to e227c27540)
Solutions
- Default the variable: $cmd = pick($cmd, '/bin/true') or set a hiera default_value
- Verify the data path: puppet lookup --node <n> profile::exec::command --explain shows which layer failed to supply it
- Conditionally declare the exec only when the command is set (if $cmd { exec { ... } })
- Ensure the value is a plain string, not structured data
Example fix
# before
exec { 'run-migration': command => $migration_cmd } # undef => ArgumentError
# after
$migration_cmd = pick(lookup('app::migration_cmd', { 'default_value' => undef }), '/bin/true')
exec { 'run-migration': command => $migration_cmd } Defensive patterns
Strategy: validation
Validate before calling
$cmd = pick($cmd, '/bin/true') # or in Ruby: raise ArgumentError, 'command is required' unless command.is_a?(String) || command.is_a?(Array)
Prevention
- Default command variables with pick() or hiera default_value
- Declare exec resources only when their data is present (if $cmd { exec { ... } })
- Use puppet lookup --explain on nodes where the exec appears without a command
When it happens
Trigger: exec { 'x': command => $cmd } where $cmd is undef (hiera key missing, variable from a class not evaluated); command built by template interpolation that returned nil; passing a Hash from a lookup; arrays containing nil elements are not caught here but fail later at execution.
Common situations: Profile data refactors where a profile silently stops setting a variable an exec depends on; deep hiera merges shadowing a key with undef; node groups missing a classification layer; optional execs whose enabling class was renamed.
Related errors
- Undefined variable '%{name}'; %{reason}
- Could not find data item %{key} in any Hiera data file and n
- Please supply a parameter to perform a Hiera lookup
- %{path}: file does not contain a valid yaml hash
- Unable to parse %{message}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/5ef2e25db6609259.
Report an issue: GitHub.