puppetlabs/puppet · error · Puppet::Error
%{callee}: default expression for $%{from} tries to illegall
Error message
%{callee}: default expression for $%{from} tries to illegally access not yet evaluated $%{to} What it means
Raised by the same ParameterScope#parameter_reference_failure path, but for the opposite ordering case: the default expression of parameter $from reads parameter $to that is declared LATER in the parameter list. Because Puppet evaluates parameters in declaration order, $to has not been evaluated yet when $from's default runs, and forward references between parameter defaults are illegal. The message names both the referencing parameter ($from) and the not-yet-evaluated parameter ($to).
Source
Thrown at lib/puppet/parser/scope.rb:214
end
end
def evaluate(name, expression, scope, evaluator)
scope.with_guarded_scope do
bad = catch(:unevaluated_parameter) do
scope.new_match_scope(nil)
return as_read_only { evaluator.evaluate(expression, scope) }
end
parameter_reference_failure(name, bad)
end
end
def parameter_reference_failure(from, to)
# Parameters are evaluated in the order they have in the @params hash.
keys = @params.keys
raise Puppet::Error, _("%{callee}: expects a value for parameter $%{to}") % { callee: @callee_name, to: to } if keys.index(to) < keys.index(from)
raise Puppet::Error, _("%{callee}: default expression for $%{from} tries to illegally access not yet evaluated $%{to}") % { callee: @callee_name, from: from, to: to }
end
private :parameter_reference_failure
def initialize(parent, callee_name, param_names)
super(parent)
@callee_name = callee_name
@params = {}
param_names.each { |name| @params[name] = Access.new }
end
def [](name)
access = @params[name]
return super if access.nil?
throw(:unevaluated_parameter, name) unless access.assigned?
access.value
end
View on GitHub (pinned to e227c27540)
Solutions
- Reorder the parameter list so every referenced parameter is declared before the parameter whose default references it: `class example($b = 3, $a = $b)`.
- Pass explicit values for both parameters so neither default needs to run: `class { 'example': a => 1, b => 3 }`.
- Replace the cross-reference with a single expression or helper function both defaults can call independently.
Example fix
# before
class example(
$a = $b, # references later parameter
$b = 'default',
) { }
# after
class example(
$b = 'default',
$a = $b,
) { } Defensive patterns
Strategy: validation
Validate before calling
# Quick grep-based lint for forward references in signatures: # rg -U 'class\s+\w+\s*\(([^)]*)\)' manifests/ then, per param list, # assert every $ref inside a default refers to a param declared earlier. # Or run a catalog preview in CI: puppet apply --noop site.pp
Prevention
- Order parameters so any parameter referenced in a default is declared above the referencing parameter.
- Prefer computing shared values once (function call or top variable) instead of chaining defaults.
- Review parameter order in code review whenever parameters are inserted or reordered.
- Compile representative node catalogs in CI to catch ordering errors early.
When it happens
Trigger: `class example($a = $b, $b = 3) {}` in any form: `include example`, resource-style declaration, or a define `define x($a = $b, $b = 3)`. Evaluating $a's default calls ParameterScope#[] on unassigned $b, which throws :unevaluated_parameter('b'); since keys.index('b') > keys.index('a'), the 'default expression for $a tries to illegally access not yet evaluated $b' branch is taken. Also triggered via lambdas with ordered parameters referencing each other's defaults.
Common situations: Adding a new parameter at the top of an existing signature whose default depends on a parameter declared below it; merging two branches of a module where parameter order differs; converting a manifest function into a lambda and preserving a wrong parameter order.
Related errors
- %{callee}: expects a value for parameter $%{to}
- Function Load Error for function '%{function_name}': %{messa
- A required parameter cannot be added after an optional param
- block_param accepts max 2 arguments (type, name), got %{size
- Attempt to redefine block
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/f2b16ae2bc7e5158.
Report an issue: GitHub.