jordansissel/fpm · error · FPM::InvalidPackageConfiguration

Missing control.tar in deb source package #{package}

Error message

Missing control.tar in deb source package #{package}

What it means

When fpm reads a .deb (e.g. fpm -s deb -t rpm), it lists the ar members with 'ar t' and takes the first entry matching control.tar to derive the compression suffix. The case statement maps gz/bzip2/xz/zst/tar; the nil branch raises FPM::InvalidPackageConfiguration because fpm could not identify any control.tar.* member in a form it recognizes.

Source

Thrown at lib/fpm/package/deb.rb:363

    compression = `#{ar_cmd[0]} t #{package}`.split("\n").grep(/control.tar/).first.split(".").last
    case compression
      when "gz"
        controltar = "control.tar.gz"
        compression = "-z"
      when "bzip2","bz2"
        controltar = "control.tar.bz2"
        compression = "-j"
      when "xz"
        controltar = "control.tar.xz"
        compression = "-J"
      when "zst"
        controltar = "control.tar.zst"
        compression = "--use-compress-program 'zstd -d'"
      when 'tar'
        controltar = "control.tar"
        compression = ""
      when nil
        raise FPM::InvalidPackageConfiguration, "Missing control.tar in deb source package #{package}"
      else
        raise FPM::InvalidPackageConfiguration,
          "Unknown compression type '#{compression}' for control.tar in deb source package #{package}"
    end

    build_path("control").tap do |path|
      FileUtils.mkdir(path) if !File.directory?(path)
      # unpack the control.tar.{,gz,bz2,xz,zst} from the deb package into staging_path
      # Unpack the control tarball
      safesystem(ar_cmd[0] + " p #{package} #{controltar} | tar #{compression} -xf - -C #{path}")

      control = File.read(File.join(path, "control"))

      parse = lambda do |field|
        value = control[/^#{field.capitalize}: .*/]
        if value.nil?
          return nil
        else

View on GitHub (pinned to b6d77ba72a)

Solutions

  1. Verify the file is a real deb: ar t package.deb should list debian-binary, control.tar.*, data.tar.*
  2. Re-download or restore the deb from its original source (apt-get download, apt cache) and retry
  3. Check the file with dpkg-deb -I package.deb to confirm dpkg itself can read it
  4. If the producer is your own pipeline, fix it to emit a standards-compliant deb

Example fix

# before
fpm -s deb -t rpm broken.deb   # corrupt file

# after
# re-fetch a good artifact first:
apt-get download foo
fpm -s deb -t rpm foo_1.0_amd64.deb
Defensive patterns

Strategy: validation

Validate before calling

def readable_deb?(path)
  return false unless File.file?(path)
  members = `ar t #{Shellwords.escape(path)}`.split("\n")
  members.include?('debian-binary') && members.any? { |m| m.start_with?('control.tar') }
end

abort "not a usable deb: #{path}" unless readable_deb?(path)

Type guard

def deb_with_control_member?(path)
  File.file?(path) && `ar t #{Shellwords.escape(path)} 2>/dev/null`.split("\n").any? { |m| m =~ /\Acontrol\.tar(\.|\z)/ }
end

Try / catch

begin
  pkg.input(deb_path)
rescue FPM::InvalidPackageConfiguration => e
  raise unless e.message =~ /Missing control.tar/
  abort "#{deb_path} is corrupt (no control.tar member) -- re-download the artifact"
end

Prevention

When it happens

Trigger: Pointing -s deb at a file that is not a valid deb, or an ar archive whose control member is absent or named so that no compression suffix can be derived. Frequently the real cause is a corrupt/truncated download or an HTML error page saved with a .deb extension, so the ar listing has no control.tar member at all.

Common situations: Converting a partially downloaded .deb; a file renamed to .deb that is actually something else; artifacts produced by nonstandard tools that omit control.tar; disk-full truncation during artifact storage.

Related errors


AI-assisted analysis of jordansissel/fpm@b6d77ba72a (2026-08-21). Data as JSON: /api/errors/ea88c6cea062758d. Report an issue: GitHub.