{"record":{"id":"7179b2dfed54aace","repo":"instructure/canvas-lms","slug":"no-block-given","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"gems/canvas_unzip/lib/canvas_unzip.rb","lineNumber":118,"sourceCode":"            bytes_left -= size\n            raise SizeLimitExceeded if bytes_left < 0\n          end\n\n          files_left -= 1\n        rescue DestinationFileExists\n          add_warning(warnings, entry, :already_exists)\n        rescue Zip::CompressionMethodError\n          add_warning(warnings, entry, :unknown_compression_method)\n        rescue Errno::ENAMETOOLONG\n          add_warning(warnings, entry, :filename_too_long)\n        end\n      end\n    end\n    warnings\n  end\n\n  def self.each_entry(archive_filename)\n    raise ArgumentError, \"no block given\" unless block_given?\n\n    file = File.open(archive_filename)\n    mime_type = File.mime_type(file)\n\n    # on some systems `file` fails to recognize a zip file with no entries; fall back on using the extension\n    mime_type = File.mime_type(archive_filename) if mime_type == \"application/octet-stream\"\n\n    if [\"application/x-gzip\", \"application/gzip\"].include? mime_type\n      file = Zlib::GzipReader.new(file)\n      mime_type = \"application/x-tar\" # it may not actually be a tar though, so rescue if there's a problem\n    end\n\n    case mime_type\n    when \"application/zip\"\n      Zip::File.open(file) do |zipfile|\n        zipfile.entries.each_with_index do |zip_entry, index|\n          yield(Entry.new(zip_entry), index)\n        end","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/canvas_unzip/lib/canvas_unzip.rb#L100-L136","documentation":"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.","triggerScenarios":"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).","commonSituations":"Using each_entry for its return value (it's for streaming); wrapping each_entry in a helper that forgot &block; count/size utilities calling it without a pass-through block.","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."],"exampleFix":"// before\nCanvasUnzip.each_entry(path) # ArgumentError: no block given\n// after\nnames = []\nCanvasUnzip.each_entry(path) { |entry, _i| names << entry.name }","handlingStrategy":"validation","validationCode":"raise ArgumentError, \"block required\" unless block_given?","typeGuard":"def each_entry_safe(path, &block)\n  return enum_for(:each_entry_safe, path) unless block\n  CanvasUnzip.each_entry(path, &block)\nend","tryCatchPattern":"begin\n  CanvasUnzip.each_entry(path) { |e, i| handle(e, i) }\nrescue ArgumentError => e\n  raise e unless e.message == \"no block given\"\n  raise UsageError, \"each_entry requires a block\"\nend","preventionTips":["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"],"tags":["missing-required-argument","argument-error","block","zip"],"backgroundTag":"missing-required-argument","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"}