{"record":{"id":"e1258360a8c827ae","repo":"jordansissel/fpm","slug":"file-is-device-which-fpm-doesn-t-know-how-to-copy","errorCode":null,"errorMessage":"File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}","messagePattern":"File is device which fpm doesn't know how to copy \\(#(.+?)\\): #(.+?)","errorType":"exception","errorClass":"FPM::Util::UnsupportedSpecialFile","httpStatus":null,"severity":"error","filePath":"lib/fpm/util.rb","lineNumber":358,"sourceCode":"      st.ftype\n    end\n\n    case filetype\n    when 'fifo'\n      if File.respond_to?(:mkfifo)\n        File.mkfifo(dst)\n      elsif program_exists?(\"mkfifo\")\n        safesystem(\"mkfifo\", dst)\n      else\n        raise NamedPipeCannotBeCopied(\"Unable to copy. Cannot find program 'mkfifo' and Ruby is missing the 'File.mkfifo' method: #{src}\")\n      end\n    when 'socket'\n      require \"socket\"\n      # In 2019, Ruby's FileUtils added this as a way to \"copy\" a unix socket.\n      # Reference: https://github.com/ruby/fileutils/pull/36/files\n      UNIXServer.new(dst).close()\n    when 'characterSpecial', 'blockSpecial'\n      raise  UnsupportedSpecialFile.new(\"File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}\")\n    when 'directory'\n      FileUtils.mkdir(dst) unless File.exist? dst\n    when 'hardlink'\n      # Handle hardlinks\n      # if the file with the same dev and inode has been copied already.\n      # hard link it's copy to `dst`, otherwise make an actual copy\n      known_entry = copied_entries[[st.dev, st.ino]]\n      if known_entry\n        FileUtils.ln(known_entry, dst)\n        logger.debug(\"Copying hardlink\", :src => src, :dst => dst, :link => known_entry)\n      else\n        FileUtils.copy_entry(src, dst, preserve, false,\n                             remove_destination)\n        copied_entries[[st.dev, st.ino]] = dst\n      end\n    else\n      # Normal file, just copy it.\n      FileUtils.copy_entry(src, dst, preserve, false,","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/jordansissel/fpm/blob/b6d77ba72a560b687723376a0e5115c3a92634ad/lib/fpm/util.rb#L340-L376","documentation":"The staging copy logic explicitly refuses characterSpecial and blockSpecial files — device nodes — because packaging device files is almost never intended and would require privileged mknod at install time. The error names the File.ftype and the source path so you can locate the node.","triggerScenarios":"Running 'fpm -s dir' over a tree that contains device nodes: an extracted container rootfs or chroot with a populated /dev, a tarball that preserved device entries, or test fixtures created with mknod.","commonSituations":"Packaging a whole rootfs/chroot for redistribution; importing VM/container images whose /dev was populated; backups of / fed straight into fpm.","solutions":["Remove the device nodes from the source tree — note that fpm's --exclude prunes after staging, so it cannot preempt this raise during the initial -s dir copy","Point fpm at a sanitized copy: tar -C rootfs --exclude='./dev/*' -cf - . | tar -C clean -xf -, then package clean/","If devices are genuinely required, create them in a post-install script with mknod instead of the payload"],"exampleFix":"# before\nfpm -s dir -t deb ./rootfs   # rootfs/dev holds device nodes => UnsupportedSpecialFile\n\n# after\nmkdir clean && tar -C rootfs --exclude='./dev/*' -cf - . | tar -C clean -xf -\nfpm -s dir -t deb ./clean","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"require 'find'\n\ndef device_nodes?(root)\n  found = false\n  Find.find(root) do |f|\n    st = File.lstat(f) rescue next\n    if st.chardev? || st.blockdev?\n      found = true\n      break\n    end\n  end\n  found\nend\n\nabort 'input tree contains device nodes' if device_nodes?('./rootfs')","tryCatchPattern":"begin\n  pkg.input('./rootfs')\nrescue FPM::Util::UnsupportedSpecialFile => e\n  warn \"device node in input (#{e.message}); sanitize the tree and retry\"\nend","preventionTips":["Never package a populated /dev; exclude it when exporting rootfs images","Sanitize extracted tars with tar --exclude='./dev/*' before -s dir","Add a device-node scan as a fast CI precheck instead of failing mid-build"],"tags":["fpm","device-files","filesystem","packaging","rootfs"],"backgroundTag":"unsupported-special-file","analyzedSha":"b6d77ba72a560b687723376a0e5115c3a92634ad","analyzedAt":"2026-08-21T16:39:02.570Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}