{"record":{"id":"2c0a6f5a41d8a0cd","repo":"puppetlabs/puppet","slug":"detail-on-node-node-name","errorCode":null,"errorMessage":"#{detail} on node #{node_name}","messagePattern":"#(.+?) on node #(.+?)","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/parser/script_compiler.rb","lineNumber":60,"sourceCode":"\n    # TRANSLATORS, \"For running script\" is not user facing\n    Puppet.override(@context_overrides, \"For running script\") do\n      # TRANSLATORS \"main\" is a function name and should not be translated\n      result = Puppet::Util::Profiler.profile(_(\"Script: Evaluated main\"), [:script, :evaluate_main]) { evaluate_main }\n      if block_given?\n        yield self\n      else\n        result\n      end\n    end\n  rescue Puppet::ParseErrorWithIssue => detail\n    detail.node = node_name\n    Puppet.log_exception(detail)\n    raise\n  rescue => detail\n    message = \"#{detail} on node #{node_name}\"\n    Puppet.log_exception(detail, message)\n    raise Puppet::Error, message, detail.backtrace\n  end\n\n  # Constructs the overrides for the context\n  def context_overrides\n    {\n      :current_environment => environment,\n      :global_scope => @topscope, # 4x placeholder for new global scope\n      :loaders => @loaders, # 4x loaders\n      :rich_data => true,\n    }\n  end\n\n  # Create a script compiler for the given environment where errors are logged as coming\n  # from the given node_name\n  #\n  def initialize(environment, node_name, for_agent = false)\n    @environment = environment\n    @node_name = node_name","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/parser/script_compiler.rb#L42-L78","documentation":"This is Puppet::Parser::ScriptCompiler#compile's catch-all rescue, not a distinct failure itself. When compiling a script (the ScriptCompiler path used for one-shot script execution with an environment), any exception that is NOT a Puppet::ParseErrorWithIssue gets re-wrapped as Puppet::Error with \" on node <node_name>\" appended and logged via Puppet.log_exception. The original exception is preserved as the cause with its backtrace, so the real fault is always the wrapped `detail`.","triggerScenarios":"ScriptCompiler#compile (or the Puppet::Pal / `puppet apply`-style script entry points that use it) evaluating a script whose code raises: a failing function call, a Ruby error inside a custom function, an assert_type failure, a failed lookup — anything outside ParseErrorWithIssue. The rescue fires per-compile, tags the node name, and re-raises Puppet::Error wrapping the original.","commonSituations":"Running manifests/scripts through pal/script compilation where a custom function raises a RuntimeError; environment or loader problems surfacing as plain Ruby exceptions; users confused because the visible message is the generic '<original message> on node mynode' and the actionable detail is nested inside.","solutions":["Read the full exception chain: the wrapped original is available as the Puppet::Error's cause (or via `--trace` / Puppet.log_exception output) — fix that underlying error, not the wrapper.","Run with `--trace` (or Puppet[:trace] = true) to get the original backtrace showing which function/expression raised.","If the failure is intermittent (network, Hiera backend), make the failing call conditional/retried at the script level before re-running compile.","In Ruby embedding (pal), rescue Puppet::Error and inspect `error.cause` to branch on the real failure class."],"exampleFix":"# before (embedding pal/script compiler)\nbegin\n  compiler.compile\nrescue Puppet::Error => e\n  puts e.message        # \"RuntimeError ... on node web1\" — real cause hidden\nend\n\n# after\nbegin\n  compiler.compile\nrescue Puppet::Error => e\n  root = e.cause || e\n  puts \"#{root.class}: #{root.message}\"\n  puts root.backtrace\nend","handlingStrategy":"try-catch","validationCode":"# Validate the script cheaply before compiling:\nPuppet::Pops::Parser::EvaluatingParser.new.validate_string(script_code)\n# (catches parse-level issues; runtime failures still need rescue below)","typeGuard":null,"tryCatchPattern":"begin\n  script_compiler.compile\nrescue Puppet::ParseErrorWithIssue => e\n  # already has file/line — handle directly\n  report(e)\nrescue Puppet::Error => e\n  root = e.cause || e        # unwrap the \"on node X\" wrapper\n  report(root)\nend","preventionTips":["Always inspect error.cause (or run with --trace) — the node-suffixed message is only a wrapper.","Validate/parse scripts before compiling them in pipelines.","Keep custom functions defensive so they raise Puppet::Error subclasses with file/line instead of raw Ruby errors.","Pin environments and module versions so loader-level Ruby exceptions do not surface at compile time."],"tags":["puppet","compiler","script","wrapper","node-context"],"backgroundTag":"manifest-compile-failure","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}