{"record":{"id":"f2b16ae2bc7e5158","repo":"puppetlabs/puppet","slug":"callee-default-expression-for-from-tries-t","errorCode":null,"errorMessage":"%{callee}: default expression for $%{from} tries to illegally access not yet evaluated $%{to}","messagePattern":"%(.+?): default expression for \\$%(.+?) tries to illegally access not yet evaluated \\$%(.+?)","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/parser/scope.rb","lineNumber":214,"sourceCode":"      end\n    end\n\n    def evaluate(name, expression, scope, evaluator)\n      scope.with_guarded_scope do\n        bad = catch(:unevaluated_parameter) do\n          scope.new_match_scope(nil)\n          return as_read_only { evaluator.evaluate(expression, scope) }\n        end\n        parameter_reference_failure(name, bad)\n      end\n    end\n\n    def parameter_reference_failure(from, to)\n      # Parameters are evaluated in the order they have in the @params hash.\n      keys = @params.keys\n      raise Puppet::Error, _(\"%{callee}: expects a value for parameter $%{to}\") % { callee: @callee_name, to: to } if keys.index(to) < keys.index(from)\n\n      raise Puppet::Error, _(\"%{callee}: default expression for $%{from} tries to illegally access not yet evaluated $%{to}\") % { callee: @callee_name, from: from, to: to }\n    end\n    private :parameter_reference_failure\n\n    def initialize(parent, callee_name, param_names)\n      super(parent)\n      @callee_name = callee_name\n      @params = {}\n      param_names.each { |name| @params[name] = Access.new }\n    end\n\n    def [](name)\n      access = @params[name]\n      return super if access.nil?\n\n      throw(:unevaluated_parameter, name) unless access.assigned?\n      access.value\n    end\n","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/parser/scope.rb#L196-L232","documentation":"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).","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"# before\nclass example(\n  $a = $b,      # references later parameter\n  $b = 'default',\n) { }\n\n# after\nclass example(\n  $b = 'default',\n  $a = $b,\n) { }","handlingStrategy":"validation","validationCode":"# Quick grep-based lint for forward references in signatures:\n#   rg -U 'class\\s+\\w+\\s*\\(([^)]*)\\)' manifests/ then, per param list,\n#   assert every $ref inside a default refers to a param declared earlier.\n# Or run a catalog preview in CI: puppet apply --noop site.pp","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["puppet","dsl","parameters","ordering","forward-reference"],"backgroundTag":"parameter-evaluation-order","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}