{"record":{"id":"b00a89e5555bb3bc","repo":"instructure/canvas-lms","slug":"invalid-entry-type","errorCode":null,"errorMessage":"Invalid entry type","messagePattern":"Invalid entry type","errorType":"exception","errorClass":"CanvasUnzip::CanvasUnzipError","httpStatus":null,"severity":"error","filePath":"gems/canvas_unzip/lib/canvas_unzip.rb","lineNumber":172,"sourceCode":"\n  def self.compute_uncompressed_size(archive_filename)\n    total_size = 0\n    each_entry(archive_filename) { |entry, _index| total_size += entry.size }\n    total_size\n  end\n\n  class Entry\n    attr_reader :entry, :type\n\n    def initialize(entry)\n      case entry\n      when Zip::Entry\n        @type = :zip\n      when Gem::Package::TarReader::Entry\n        @type = :tar\n      end\n\n      raise CanvasUnzipError, \"Invalid entry type\" unless @type\n\n      @entry = entry\n    end\n\n    def symlink?\n      case type\n      when :zip\n        entry.symlink?\n      when :tar\n        entry.header.typeflag == \"2\"\n      end\n    end\n\n    delegate :directory?, :file?, to: :entry\n\n    def name\n      @name ||= case type\n                when :zip","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/canvas_unzip/lib/canvas_unzip.rb#L154-L190","documentation":"CanvasUnzip::Entry#initialize wraps either a Zip::Entry or a Gem::Package::TarReader::Entry and raises CanvasUnzipError \"Invalid entry type\" if the object passed is neither — it cannot determine the archive type (@type stays nil). This is an internal invariant; it surfaces when Entry is constructed with an unsupported/foreign object.","triggerScenarios":"Calling CanvasUnzip::Entry.new(some_other_object) directly; library-internal changes where a new entry class (e.g. from a different zip gem version) isn't in the case statement; monkey-patching or stubbing entries in tests with doubles.","commonSituations":"Custom extraction code bypassing each_entry and building Entry objects manually; gem version upgrades changing Zip::Entry's class/namespace; test fakes passed where a real entry is expected.","solutions":["Obtain entries via CanvasUnzip.each_entry / extract_archive instead of constructing Entry yourself.","Check which class the object actually is (obj.class) and whether the installed rubyzip/gem versions match what CanvasUnzip expects (update Gemfile).","If you must construct Entry, pass a genuine Zip::Entry or Gem::Package::TarReader::Entry.","Rescue CanvasUnzip::CanvasUnzipError in custom pipelines and log the offending entry class."],"exampleFix":"// before\nentry = CanvasUnzip::Entry.new(OpenStruct.new(name: \"a.txt\")) # raises\n// after\nCanvasUnzip.each_entry(path) { |entry, _i| process(entry) } # entries built internally","handlingStrategy":"try-catch","validationCode":"raise TypeError, \"unsupported entry class #{obj.class}\" unless obj.is_a?(Zip::Entry) || obj.is_a?(Gem::Package::TarReader::Entry)","typeGuard":"def valid_entry?(obj)\n  obj.is_a?(Zip::Entry) || obj.is_a?(Gem::Package::TarReader::Entry)\nend","tryCatchPattern":"begin\n  entry = CanvasUnzip::Entry.new(obj)\nrescue CanvasUnzip::CanvasUnzipError\n  Rails.logger.warn(\"cannot wrap entry of class #{obj.class}\")\n  nil\nend","preventionTips":["Get entries from each_entry, not manual construction","Pin rubyzip versions compatible with canvas_unzip","Don't stub entries with arbitrary doubles in tests","Check obj.class when wrapping manually"],"tags":["type-mismatch","internal","zip","tar"],"backgroundTag":"type-mismatch","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}