instructure/canvas-lms · error · ArgumentError
no block given
Error message
no block given
What it means
CanvasUnzip.each_entry iterates archive entries via a caller-supplied block and raises ArgumentError "no block given" when invoked without one. It's an internal/low-level API whose only output channel is yielding (entry, index), so a block is mandatory.
Solutions
- Always pass a block: CanvasUnzip.each_entry(path) { |entry, i| ... }.
- If wrapping, forward the block explicitly: def self.each_entry(path, &block); CanvasUnzip.each_entry(path, &block); end.
- Prefer extract_archive with a block, or compute_uncompressed_size, for common use cases.
Example fix
// before
CanvasUnzip.each_entry(path) # ArgumentError: no block given
// after
names = []
CanvasUnzip.each_entry(path) { |entry, _i| names << entry.name } Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, "block required" unless block_given?
Type guard
def each_entry_safe(path, &block) return enum_for(:each_entry_safe, path) unless block CanvasUnzip.each_entry(path, &block) end
Try / catch
begin
CanvasUnzip.each_entry(path) { |e, i| handle(e, i) }
rescue ArgumentError => e
raise e unless e.message == "no block given"
raise UsageError, "each_entry requires a block"
end Prevention
- Forward &block in wrapper methods
- Don't call each_entry for a return value
- Prefer extract_archive for common flows
- Use enum_for to make block optional in helpers
When it happens
Trigger: Calling CanvasUnzip.each_entry('archive.zip') directly without a block; forwarding methods that drop the implicit block (define_method without &block, method_missing chains losing the block).
Common situations: Using each_entry for its return value (it's for streaming); wrapping each_entry in a helper that forgot █ count/size utilities calling it without a pass-through block.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Needs block or destination path
- File not found
- block is required if module_name is not passed
- Cannot generate a services JWT without a 'sub' entry
- Cannot include a concatenation in a merge.
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/7179b2dfed54aace.
Report an issue: GitHub.
Appendix: source
Thrown at gems/canvas_unzip/lib/canvas_unzip.rb:118
bytes_left -= size
raise SizeLimitExceeded if bytes_left < 0
end
files_left -= 1
rescue DestinationFileExists
add_warning(warnings, entry, :already_exists)
rescue Zip::CompressionMethodError
add_warning(warnings, entry, :unknown_compression_method)
rescue Errno::ENAMETOOLONG
add_warning(warnings, entry, :filename_too_long)
end
end
end
warnings
end
def self.each_entry(archive_filename)
raise ArgumentError, "no block given" unless block_given?
file = File.open(archive_filename)
mime_type = File.mime_type(file)
# on some systems `file` fails to recognize a zip file with no entries; fall back on using the extension
mime_type = File.mime_type(archive_filename) if mime_type == "application/octet-stream"
if ["application/x-gzip", "application/gzip"].include? mime_type
file = Zlib::GzipReader.new(file)
mime_type = "application/x-tar" # it may not actually be a tar though, so rescue if there's a problem
end
case mime_type
when "application/zip"
Zip::File.open(file) do |zipfile|
zipfile.entries.each_with_index do |zip_entry, index|
yield(Entry.new(zip_entry), index)
endView on GitHub (pinned to 1c9f0bb801)