jordansissel/fpm · error · FPM::Package::InvalidArgument
Options file already loaded once. Refusing to load a second
Error message
Options file already loaded once. Refusing to load a second time. Maybe a file tries to load itself? Path: #{path} What it means
load_options records every --fpm-options-file path in @loaded_files; encountering the same path a second time raises FPM::Package::InvalidArgument to break infinite recursion. In practice an options file includes itself, or two files include each other in a cycle.
Source
Thrown at lib/fpm/command.rb:610
logger.warn("Additional options: #{flags.join " "}") if flags.size > 0
logger.warn("Additional arguments: #{args.join " "}") if args.size > 0
ARGV.unshift(*flags)
ARGV.push(*args)
super(run_args)
rescue FPM::Package::InvalidArgument => e
logger.error("Invalid package argument: #{e}")
return 1
end # def run
def load_options(path)
@loaded_files ||= []
if @loaded_files.include?(path)
#logger.error("Options file was already loaded once. Refusing to load a second time.", :path => path)
raise FPM::Package::InvalidArgument, "Options file already loaded once. Refusing to load a second time. Maybe a file tries to load itself? Path: #{path}"
end
if !File.exist?(path)
logger.fatal("Cannot load options from file because the file doesn't exist.", :path => path)
end
if !File.readable?(path)
logger.fatal("Cannot load options from file because the file isn't readable.", :path => path)
end
@loaded_files << path
logger.info("Loading flags from file", :path => path)
# Safety check, abort if the file is huge. Arbitrarily chosen limit is 100kb
stat = File.stat(path)
max = 100 * 1024
if stat.size > maxView on GitHub (pinned to b6d77ba72a)
Solutions
- Remove the self-referencing --fpm-options-file line from the file
- Restructure so one base file holds shared flags and only leaf configs include it (keep the include graph a tree)
- Grep both sides of a cross-include pair and drop one direction
Example fix
# before: fpm.conf contains its own path --fpm-options-file ./fpm.conf --log debug # after: fpm.conf --log debug
Defensive patterns
Strategy: validation
Validate before calling
path = File.expand_path('fpm.conf')
File.readlines(path).each do |line|
args = line.split
if (i = args.index('--fpm-options-file')) && args[i + 1] && File.expand_path(args[i + 1]) == path
abort 'options file includes itself; remove the self-referencing line'
end
end Try / catch
begin
FPM::Command.run(%w[--fpm-options-file fpm.conf --version])
rescue FPM::Package::InvalidArgument => e
abort "options-file cycle detected: #{e.message}"
end Prevention
- Keep --fpm-options-file references acyclic: one shared base file included only by leaf configs
- Never leave a file's own --fpm-options-file line inside the file itself
- Smoke-test option files with 'fpm --fpm-options-file <file> --version' in CI
When it happens
Trigger: An options file containing its own path (--fpm-options-file ./fpm.conf listed inside fpm.conf); file A including B while B includes A; the same file referenced twice on one command line.
Common situations: Copy-pasting example configs that self-reference; refactoring shared flags into mutually-including files; generated configs that append their own loader line on each run.
Related errors
- Options file given to --fpm-options-file is seems too large.
- Invalid log level, #{v.inspect}. Must be one of: #{loglevels
- The given workdir '#{workdir}' does not exist.
- The given workdir '#{workdir}' must be a directory.
- #{self.class.name} does not yet support reading #{self.type}
AI-assisted analysis of jordansissel/fpm@b6d77ba72a (2026-08-21).
Data as JSON: /api/errors/c37c639b5a8f5b15.
Report an issue: GitHub.