puppetlabs/puppet · error · Puppet::Error
There is more than one '%{basename}' script in %{dir}
Error message
There is more than one '%{basename}' script in %{dir} What it means
When trusted_external_command points to a directory, Puppet runs every executable file inside it and builds external trusted facts keyed by each file's basename without extension (servicenow.rb -> 'servicenow'). If two executable files share the same basename (servicenow.rb and servicenow.sh), the second one hits an occupied key and Puppet::Error 'There is more than one X script in DIR' aborts trusted-fact retrieval during node classification.
Source
Thrown at lib/puppet/trusted_external.rb:29
if setting_type == :file
return fetch_data(command, certname)
end
# command is a directory. Thus, data is a hash of <basename> => <data> for
# each executable file in command. For example, if the files 'servicenow.rb',
# 'unicorn.sh' are in command, then data is the following hash:
# { 'servicenow' => <servicenow.rb output>, 'unicorn' => <unicorn.sh output> }
data = {}
Puppet::FileSystem.children(command).each do |file|
abs_path = Puppet::FileSystem.expand_path(file)
executable_file = Puppet::FileSystem.file?(abs_path) && Puppet::FileSystem.executable?(abs_path)
unless executable_file
Puppet.debug { _("Skipping non-executable file %{file}") % { file: abs_path } }
next
end
basename = file.basename(file.extname).to_s
unless data[basename].nil?
raise Puppet::Error, _("There is more than one '%{basename}' script in %{dir}") % { basename: basename, dir: command }
end
data[basename] = fetch_data(abs_path, certname)
end
data
end
module_function :retrieve
def fetch_data(command, certname)
result = Puppet::Util::Execution.execute([command, certname], {
:combine => false,
:failonfail => true,
})
JSON.parse(result)
end
module_function :fetch_data
end
View on GitHub (pinned to e227c27540)
Solutions
- List the directory and remove or rename the duplicate so each basename is unique: ls -l <dir>, then delete the stale script
- Strip the executable bit from backups (chmod -x custom.rb.bak) — non-executable files are skipped with a debug message
- If both scripts are legitimate, rename one so the fact keys differ (servicenow_v2.sh)
- Verify recovery with puppet facts --debug, checking 'Retrieving trusted external data' completes
Example fix
# before (/etc/puppet/trusted-external contains) # servicenow.rb (executable) # servicenow.sh (executable) => Puppet::Error # after rm /etc/puppet/trusted-external/servicenow.sh # or: chmod -x servicenow.sh
Defensive patterns
Strategy: validation
Validate before calling
require 'set'
dir = Puppet[:trusted_external_command]
seen = {}
Dir.children(dir).each do |f|
next unless File.executable?(File.join(dir, f))
base = File.basename(f, File.extname(f))
seen[base] ||= 0
seen[base] += 1
end
dupes = seen.select { |_, c| c > 1 }.keys
raise "duplicate trusted-external basenames: #{dupes.join(', ')}" unless dupes.empty? Prevention
- Deploy trusted-facts scripts from one source (package or puppet) so stale copies never linger
- chmod -x backups; non-executable files are skipped by design
- Name scripts uniquely per fact key (servicenow.rb vs servicenow_v2.sh)
When it happens
Trigger: Puppet[:trusted_external_command] set to a directory that contains both custom.rb and custom.sh (or custom and custom.py). Only executable regular files participate; backups like custom.rb.bak are skipped only if not executable, but backup scripts that remain executable (custom.rb.orig chmod +x, or editor droppings saved with the executable bit) collide.
Common situations: Iterating on trusted-facts scripts and leaving old copies (foo.sh after rewriting to foo.rb); deploying scripts with a package manager that leaves .rpmnew/.dpkg-dist copies executable; operators adding a .bak copy for rollback while keeping the exec bit.
Related errors
- Diff is not supported on this platform
- Paths must be fully qualified
- Invalid argument '%{var}' at %{error_location}
- attribute %{label}[%{key}] is defined as both a constant and
- Entry '#{line.chomp}' is unsupported and will be ignored at
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/5a3e33f50d358788.
Report an issue: GitHub.