instructure/canvas-lms · error · CanvasUnzip::CanvasUnzipError
Invalid entry type
Error message
Invalid entry type
What it means
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.
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.
Example fix
// before
entry = CanvasUnzip::Entry.new(OpenStruct.new(name: "a.txt")) # raises
// after
CanvasUnzip.each_entry(path) { |entry, _i| process(entry) } # entries built internally Defensive patterns
Strategy: try-catch
Validate before calling
raise TypeError, "unsupported entry class #{obj.class}" unless obj.is_a?(Zip::Entry) || obj.is_a?(Gem::Package::TarReader::Entry) Type guard
def valid_entry?(obj) obj.is_a?(Zip::Entry) || obj.is_a?(Gem::Package::TarReader::Entry) end
Try / catch
begin
entry = CanvasUnzip::Entry.new(obj)
rescue CanvasUnzip::CanvasUnzipError
Rails.logger.warn("cannot wrap entry of class #{obj.class}")
nil
end Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- all elements must be User objects
- Destination '# ' already exists
- File not found
- filter values must be JSON-compatible types
- # is not a valid StringMap
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/b00a89e5555bb3bc.
Report an issue: GitHub.
Appendix: source
Thrown at gems/canvas_unzip/lib/canvas_unzip.rb:172
def self.compute_uncompressed_size(archive_filename)
total_size = 0
each_entry(archive_filename) { |entry, _index| total_size += entry.size }
total_size
end
class Entry
attr_reader :entry, :type
def initialize(entry)
case entry
when Zip::Entry
@type = :zip
when Gem::Package::TarReader::Entry
@type = :tar
end
raise CanvasUnzipError, "Invalid entry type" unless @type
@entry = entry
end
def symlink?
case type
when :zip
entry.symlink?
when :tar
entry.header.typeflag == "2"
end
end
delegate :directory?, :file?, to: :entry
def name
@name ||= case type
when :zipView on GitHub (pinned to 1c9f0bb801)