{"record":{"id":"8449e3de2a7704ca","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby-edge/concurrent/channel.rb","lineNumber":194,"sourceCode":"      (item = do_poll) == Concurrent::NULL ? nil : item\n    end\n\n    def poll!\n      item = do_poll\n      raise Error if item == Concurrent::NULL\n      item\n    end\n\n    def poll?\n      if (item = do_poll) == Concurrent::NULL\n        Concurrent::Maybe.nothing\n      else\n        Concurrent::Maybe.just(item)\n      end\n    end\n\n    def each\n      raise ArgumentError.new('no block given') unless block_given?\n      loop do\n        item, more = do_next\n        if item != Concurrent::NULL\n          yield(item)\n        elsif !more\n          break\n        end\n      end\n    end\n\n    class << self\n      def timer(seconds)\n        Channel.new(Buffer::Timer.new(seconds))\n      end\n      alias_method :after, :timer\n\n      def ticker(interval)\n        Channel.new(Buffer::Ticker.new(interval))","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby-edge/concurrent/channel.rb#L176-L212","documentation":"Channel#each is the enumeration loop that pops items from the channel until it is closed and drained. Unlike core Ruby enumerables, this implementation does not return a lazy Enumerator when called without a block - it raises ArgumentError immediately, because the block is the only way to consume each item.","triggerScenarios":"channel.each invoked with no block - a bare channel.each statement, or channel.each(&nil) through a helper whose block variable was never set.","commonSituations":"Refactoring each { ... } into chains like each_with_object or map (which call each without a consumer block of the right shape); passing a conditional block (cond && proc {...}) that evaluates to nil; expecting Hash#each-style Enumerator semantics such as channel.each.each_slice(10).","solutions":["Pass the consuming block: channel.each { |item| handle(item) }.","If you need items as a collection, drain explicitly with take/pop in a loop (after closing the channel) instead of relying on Enumerator chaining.","In wrappers that forward to each, check block_given? and raise a clearer error naming your API."],"exampleFix":"# before\nchannel.each   # raises: no block given\n\n# after\nchannel.each { |item| handle(item) }","handlingStrategy":"validation","validationCode":"def drain(channel)\n  raise ArgumentError, 'a consumer block is required' unless block_given?\n  channel.each { |item| yield(item) }\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["This each never returns an Enumerator - do not chain each.each_slice or each.lazy on a channel.","Check block_given? early in wrappers so the error names your API, not the library's.","Close the channel before draining it into a collection."],"tags":["ruby","concurrent-ruby","channel","enumerable","block","argumenterror"],"backgroundTag":"missing-block-argument","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}