jordansissel/fpm · error · FPM::Util::ProcessFailed
'#{editor}' failed (exit code #{$?.exitstatus}) Full command
Error message
'#{editor}' failed (exit code #{$?.exitstatus}) Full command was: #{command} What it means
With --edit, fpm writes the generated spec/metadata to a temp file and launches an editor via system(): the program from $FPM_EDITOR, else $EDITOR, else 'vi'. If that editor process exits non-zero, FPM::Util::ProcessFailed is raised with the exit status and the full command line. The failure belongs to the editor process, not to fpm's packaging logic.
Source
Thrown at lib/fpm/package.rb:372
def to_s(fmt=nil)
fmt = "NAME.EXTENSION" if fmt.nil?
return fmt.gsub("ARCH", to_s_arch) \
.gsub("NAME", to_s_name) \
.gsub("FULLVERSION", to_s_fullversion) \
.gsub("VERSION", to_s_version) \
.gsub("ITERATION", to_s_iteration) \
.gsub("EPOCH", to_s_epoch) \
.gsub("TYPE", to_s_type) \
.gsub("EXTENSION", to_s_extension)
end # def to_s
def edit_file(path)
editor = ENV['FPM_EDITOR'] || ENV['EDITOR'] || 'vi'
logger.info("Launching editor", :file => path)
command = "#{editor} #{Shellwords.escape(path)}"
system("#{editor} #{Shellwords.escape(path)}")
if !$?.success?
raise ProcessFailed.new("'#{editor}' failed (exit code " \
"#{$?.exitstatus}) Full command was: " \
"#{command}");
end
if File.size(path) == 0
raise "Empty file after editing: #{path.inspect}"
end
end # def edit_file
# This method removes excluded files from the staging_path. Subclasses can
# remove the files during the input phase rather than deleting them here
def exclude
return if attributes[:excludes].nil?
if @attributes.include?(:prefix)
installdir = staging_path(@attributes[:prefix])
else
installdir = staging_pathView on GitHub (pinned to b6d77ba72a)
Solutions
- Export a working editor before running: FPM_EDITOR=vim (and confirm 'which vim' succeeds)
- Drop --edit in non-interactive contexts and supply fields via flags (--description, --after-install, --template-scripts, ...)
- If the editor is a wrapper, ensure it exits 0 on success; test with '$FPM_EDITOR /tmp/probe'
- For scripted edits, point FPM_EDITOR at a non-interactive filter (e.g. a sed-based wrapper)
Example fix
# before (CI job, no TTY) fpm --edit -s dir -t deb ./app # vi fails without a terminal => ProcessFailed # after: no interactive edit; set fields explicitly FPM_EDITOR=vim fpm --edit -s dir -t deb ./app # local, interactive use only fpm -s dir -t deb --description 'My app' ./app # CI-safe
Defensive patterns
Strategy: validation
Validate before calling
editor = (ENV['FPM_EDITOR'] || ENV['EDITOR'] || 'vi').split(' ').first
unless system('which', editor, out: File::NULL, err: File::NULL)
abort "editor '#{editor}' not found; set FPM_EDITOR or drop --edit"
end Try / catch
begin
# invoking fpm with --edit programmatically
rescue FPM::Util::ProcessFailed => e
abort "editor failed: #{e.message}" # includes exit code and full command
end Prevention
- Never use --edit in CI/automation; supply metadata through flags or --template-scripts instead
- Export FPM_EDITOR explicitly in scripts rather than relying on ambient EDITOR state
- Ensure wrapper editors exit 0 on success; test them with '$FPM_EDITOR /tmp/probe' before wiring into fpm
When it happens
Trigger: Running 'fpm --edit ...' where FPM_EDITOR/EDITOR points to a missing or crashing binary; a headless/CI shell with no TTY so vi exits with an error; the editor being killed or quitting with a non-zero status.
Common situations: CI pipelines that inherited --edit from a local alias; EDITOR set to a GUI editor needing a display; wrapper-script editors whose last command returns non-zero; minimal containers where even the default vi is absent.
Related errors
- File already exists, refusing to continue: #{output_path}
- #{program}
- #{program} failed (exit code #{exit_code}). Full command was
- #{self.class.name} does not yet support reading #{self.type}
- #{self.class.name} does not yet support creating #{self.type
AI-assisted analysis of jordansissel/fpm@b6d77ba72a (2026-08-21).
Data as JSON: /api/errors/af09c62fe0088895.
Report an issue: GitHub.