{"record":{"id":"b68267812b97729a","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-b68267","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/selector.rb","lineNumber":30,"sourceCode":"    class Selector\n\n      def initialize\n        @clauses = []\n        @error_handler = nil\n      end\n\n      def case(channel, action, message = nil, &block)\n        if [:take, :poll, :receive, :~].include?(action)\n          take(channel, &block)\n        elsif [:put, :offer, :send, :<<].include?(action)\n          put(channel, message, &block)\n        else\n          raise ArgumentError.new('invalid action')\n        end\n      end\n\n      def take(channel, &block)\n        raise ArgumentError.new('no block given') unless block_given?\n        @clauses << TakeClause.new(channel, block)\n      end\n      alias_method :receive, :take\n\n      def put(channel, message, &block)\n        @clauses << PutClause.new(channel, message, block)\n      end\n      alias_method :send, :put\n\n      def after(seconds, &block)\n        @clauses << AfterClause.new(seconds, block)\n      end\n      alias_method :timeout, :after\n\n      def default(&block)\n        raise ArgumentError.new('no block given') unless block_given?\n        @clauses << DefaultClause.new(block)\n      end","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby-edge/concurrent/channel/selector.rb#L12-L48","documentation":"Inside a Channel.select block, sel.take(channel) registers a take clause whose block is invoked with the received value when the clause wins. Without a block the clause could never deliver its result, so registration raises ArgumentError.","triggerScenarios":"sel.take(ch) with no block in a select DSL - typically programmatic registration (channels.each { |ch| sel.take(ch) }) that forgot the block, or sel.take(ch, &nil) via a nil handler variable.","commonSituations":"Registering clauses in a loop over a channel list and dropping the per-clause block; refactoring a literal block into a variable that ends up nil; building selectors from config where the handler key is missing.","solutions":["Always pass the result block: sel.take(ch) { |value| handle(value) }.","When registering many takes, build the block in the loop so each clause has one: channels.each { |ch| sel.take(ch) { |v| handle(ch, v) } }.","Validate handler presence before building the selector when wiring from config."],"exampleFix":"# before\nchannels.each { |ch| sel.take(ch) }   # no block -> raises\n\n# after\nchannels.each { |ch| sel.take(ch) { |value| handle(ch, value) } }","handlingStrategy":"validation","validationCode":"channels.each do |ch|\n  raise ArgumentError, 'handler block missing' unless handler\n  sel.take(ch, &handler)\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every clause registrar (take/put/after/default/error) needs a block - treat it as part of the DSL signature.","When building clauses from config, validate handler presence before entering Channel.select.","Prefer constructing blocks inline in loops rather than passing possibly-nil variables with &."],"tags":["ruby","concurrent-ruby","selector","channel","block","argumenterror"],"backgroundTag":"missing-block-argument","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}