puppetlabs/puppet · error · ArgumentError
Undefined variable '%{name}'; %{reason}
Error message
Undefined variable '%{name}'; %{reason} What it means
Hiera::Scope#safe_lookupvar wraps the real puppet scope's lookupvar; when the scope rejects the lookup it throws :undefined_variable with a reason, and with Puppet[:strict] = :error the catch block converts that into an ArgumentError naming the variable and reason. At :warning it emits a warn_once notice instead; at :off it silently returns nil.
Source
Thrown at lib/hiera/scope.rb:52
end
# This method is used to handle the throw of :undefined_variable since when
# strict variables is not in effect, missing handling of the throw leads to
# a more expensive code path.
#
def safe_lookupvar(key)
reason = catch :undefined_variable do
return @real.lookupvar(key)
end
case Puppet[:strict]
when :off
# do nothing
when :warning
Puppet.warn_once(Puppet::Parser::Scope::UNDEFINED_VARIABLES_KIND, _("Variable: %{name}") % { name: key },
_("Undefined variable '%{name}'; %{reason}") % { name: key, reason: reason })
when :error
raise ArgumentError, _("Undefined variable '%{name}'; %{reason}") % { name: key, reason: reason }
end
nil
end
private :safe_lookupvar
def exist?(key)
CALLING_KEYS.include?(key) || @real.exist?(key)
end
def include?(key)
CALLING_KEYS.include?(key) || @real.include?(key)
end
def catalog
@real.catalog
end
def resourceView on GitHub (pinned to e227c27540)
Solutions
- Set the variable (or fix its spelling) before the lookup — assign it in the manifest/profile
- Make absence legal by giving the lookup a fallback: lookup('my::key', 'default') or hiera('key', 'default')
- Temporarily relax strictness in puppet.conf: strict = warning (and/or strict_variables = false) while migrating
- Run puppet lookup --explain to see exactly which variable lookup fails and why
Example fix
# data/myapp.yaml
# before
server: "%{undefined_hostname}" # strict=error -> ArgumentError
# after
server: "%{lookup('facts.networking.hostname', 'unknown')}" Defensive patterns
Strategy: validation
Validate before calling
key = 'my_var'
unless scope.exist?(key) # Hiera::Scope#exist? / include? are public
Puppet.warning("skipping lookup of undefined #{key}")
return nil
end
scope.lookupvar(key) Try / catch
begin value = scope.lookupvar(key) rescue ArgumentError => e raise unless e.message =~ /Undefined variable/ default_value # strict=error path: degrade to a default end
Prevention
- Run with strict = warning in CI first to surface all undefined variables before enabling error
- Use scope.exist?(key)/include?(key) before lookups on optional data
- Always give lookup()/hiera() calls a default when absence is legitimate
When it happens
Trigger: Interpolating a never-assigned variable in hiera data (%{undefined_var}) or calling lookupvar for a missing name while running with strict_variables = true and strict = error (the Puppet 8 defaults).
Common situations: Upgrading manifests from older Puppet's loose variable behavior to strict_variables; typos in variable names inside hiera YAML interpolation; relying on facts or class variables that are only set on some node roles.
Related errors
- Undefined variable '%{name}'; %{reason}
- Cannot assign to a numeric match result variable '$%{name}'
- 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
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/60117a318801f45c.
Report an issue: GitHub.