{"record":{"id":"f366900173450e8a","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-f36690","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/dataflow.rb","lineNumber":58,"sourceCode":"    call_dataflow(:value, executor, *inputs, &block)\n  end\n  module_function :dataflow_with\n\n  def dataflow!(*inputs, &block)\n    dataflow_with!(Concurrent.global_io_executor, *inputs, &block)\n  end\n  module_function :dataflow!\n\n  def dataflow_with!(executor, *inputs, &block)\n    call_dataflow(:value!, executor, *inputs, &block)\n  end\n  module_function :dataflow_with!\n\n  private\n\n  def call_dataflow(method, executor, *inputs, &block)\n    raise ArgumentError.new('an executor must be provided') if executor.nil?\n    raise ArgumentError.new('no block given') unless block_given?\n    unless inputs.all? { |input| input.is_a? IVar }\n      raise ArgumentError.new(\"Not all dependencies are IVars.\\nDependencies: #{ inputs.inspect }\")\n    end\n\n    result = Future.new(executor: executor) do\n      values = inputs.map { |input| input.send(method) }\n      block.call(*values)\n    end\n\n    if inputs.empty?\n      result.execute\n    else\n      counter = DependencyCounter.new(inputs.size) { result.execute }\n\n      inputs.each do |input|\n        input.add_observer counter\n      end\n    end","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/dataflow.rb#L40-L76","documentation":"Concurrent.dataflow, dataflow!, dataflow_with and dataflow_with! all funnel into the private call_dataflow, which requires a block describing the computation to run once every input IVar resolves. It raises ArgumentError('no block given') when that block is missing. This is a fail-fast API contract check at call time, not a concurrency failure.","triggerScenarios":"Calling Concurrent.dataflow(f1, f2) with no block; passing the computation as a positional argument instead of a block (Concurrent.dataflow(f1, ->(v) { v + 1 })); delegating through your own wrapper method that takes &block but whose caller supplied none; dynamic dispatch (define_method/instance_exec) that drops the block.","commonSituations":"Refactoring drops the trailing block; the callable is stored in a local and passed without the & sigil; a DSL wrapper makes the block optional while dataflow requires it; copy-pasted example code using method objects where no block reaches dataflow.","solutions":["Pass the computation as a literal block: Concurrent.dataflow(f1, f2) { |a, b| a + b }","When the callable is in a variable, pass it with &: Concurrent.dataflow(f1, &handler)","In wrapper methods, check block_given? before delegating and raise your own descriptive error","When dispatching dynamically, capture the block as &proc and forward it intact"],"exampleFix":"# before\nConcurrent.dataflow(future_a, future_b, ->(a, b) { a + b })\n# after\nConcurrent.dataflow(future_a, future_b) { |a, b| a + b }","handlingStrategy":"validation","validationCode":"fail ArgumentError, 'dataflow requires a computation block' unless task.respond_to?(:call)\nConcurrent.dataflow(*inputs, &task)","typeGuard":null,"tryCatchPattern":"begin\n  Concurrent.dataflow(*inputs) { |*vs| compute(*vs) }\nrescue ArgumentError => e\n  raise unless e.message == 'no block given'\n  raise ArgumentError, \"dataflow called without a block from #{caller.first}\"\nend","preventionTips":["Pass callables with & whenever they come from a variable","Forward &block explicitly in every wrapper around dataflow","Treat a missing computation as a programming error: fail fast in your own API with caller context"],"tags":["ruby","concurrency","dataflow","argument-error","missing-block"],"backgroundTag":"missing-block-argument","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}