puppetlabs/puppet · error · Puppet::Error
Could not load external node results for %{name}: %{detail}
Error message
Could not load external node results for %{name}: %{detail} What it means
Catch-all wrapper around the exec node terminus's translate() step: any failure while parsing the ENC script's output with YAML.safe_load, or while normalizing its keys, is re-raised as Puppet::Error with the node name and the underlying detail. It covers malformed YAML (Psych::SyntaxError), disallowed classes (Aliases, unexpected tags) under safe_load, and non-hash-like structures (e.g., a scalar top level making each_with_object raise NoMethodError).
Source
Thrown at lib/puppet/indirector/node/exec.rb:68
node.fact_merge(facts)
node
end
# Translate the yaml string into Ruby objects.
def translate(name, output)
Puppet::Util::Yaml.safe_load(output, [Symbol]).each_with_object({}) do |data, hash|
case data[0]
when String
hash[data[0].intern] = data[1]
when Symbol
hash[data[0]] = data[1]
else
raise Puppet::Error, _("key is a %{klass}, not a string or symbol") % { klass: data[0].class }
end
end
rescue => detail
raise Puppet::Error, _("Could not load external node results for %{name}: %{detail}") % { name: name, detail: detail }, detail.backtrace
end
end
View on GitHub (pinned to e227c27540)
Solutions
- Run the ENC manually with a node name and validate the output: /path/to/enc.sh nodename.example.com | ruby -ryaml -e 'YAML.safe_load(STDIN, [Symbol]) or raise'
- Send all diagnostics to stderr, never stdout, in the ENC script
- Ensure the ENC always prints exactly one YAML hash (even an empty one: '--- {}') on success
- If the output uses anchors/aliases, remove them or use YAML.safe_load(..., aliases: true) semantics on the ENC side by expanding aliases before dumping
Example fix
# before (ENC script) puts "Looking up node..." # pollutes stdout -> Psych syntax error puts YAML.dump(result) # after warn "Looking up node..." # stderr only puts YAML.dump(result) # stdout is pure YAML
Defensive patterns
Strategy: try-catch
Validate before calling
output = `#{enc_script} #{Shellwords.escape(name)} 2>/dev/null`
require 'yaml'
begin
YAML.safe_load(output, [Symbol])
rescue Psych::Exception => e
raise Puppet::Error, "ENC output is not valid YAML: #{e.message}"
end Try / catch
begin
node = Puppet::Node.indirection.find(certname)
rescue Puppet::Error => e
raise unless e.message =~ /Could not load external node results/
# capture raw ENC output for diagnosis and re-raise with context
raw = `#{Puppet[:external_nodes]} #{Shellwords.escape(certname)}`
raise Puppet::Error, "ENC raw output was: #{raw[0,200]}"
end Prevention
- ENC scripts must write diagnostics to stderr only
- Always exit non-zero and print nothing on failure so failures are distinguishable from bad YAML
- Smoke-test ENC output through YAML.safe_load in a CI job
When it happens
Trigger: ENC script prints warnings/deprecation notices before the YAML (making stdout invalid YAML), prints an empty string (safe_load returns nil/false and iteration fails), emits YAML aliases or symbols not whitelisted by safe_load, or crashes and the shell prints a stack trace to stdout which the terminus then tries to parse.
Common situations: ENC scripts that log to stdout instead of stderr; Ruby 3.x Psych defaults rejecting aliases; ENCs that silently die (exit non-zero) with stderr going to logs but stdout empty; scripts emitting multiple YAML documents.
Related errors
- key is a %{klass}, not a string or symbol
- Unable to parse %{message}
- You must set the 'external_nodes' parameter to use the exter
- Could not parse YAML data for %{indirection} %{request}: %{d
- #{path}: #{detail.message}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/5805dd7300af659a.
Report an issue: GitHub.