{"record":{"id":"bf26d4b2d5d73f0c","repo":"ruby-concurrency/concurrent-ruby","slug":"not-all-dependencies-are-ivars-dependencies-i","errorCode":null,"errorMessage":"Not all dependencies are IVars.\nDependencies: #{ inputs.inspect }","messagePattern":"Not all dependencies are IVars\\.\nDependencies: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/dataflow.rb","lineNumber":60,"sourceCode":"  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\n\n    result","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/dataflow.rb#L42-L78","documentation":"Every input to the Concurrent.dataflow* family must be an IVar (Future, Promise, IVar, or a prior dataflow result) because dataflow works by observing completion of those objects. call_dataflow checks inputs.all? { |i| i.is_a?(Concurrent::IVar) } and raises ArgumentError including the inspected dependency list when any input fails. Raw Ruby values are rejected because there is nothing to wait on.","triggerScenarios":"Concurrent.dataflow(2, future_a) { |a, b| a + b } mixing a raw Integer with a Future; passing the Array itself instead of splatting (dataflow(futures) vs dataflow(*futures)); a dependency variable that evaluated to nil; feeding Threads, plain procs, or monads from other libraries as dependencies.","commonSituations":"Seeding a dataflow graph with constant inputs without wrapping them in Concurrent.future; refactoring Futures into plain values and forgetting the wrapper; splat bugs where the whole array arrives as one argument; a lookup method returning nil for a missing dependency.","solutions":["Wrap every non-IVar input: Concurrent.dataflow(Concurrent.future { 2 }, future_a) { |a, b| a + b }","Splat arrays of dependencies: Concurrent.dataflow(*futures) { |*vs| ... }","Pre-check inputs.all? { |i| i.is_a?(Concurrent::IVar) } and raise early with your own message","Guard against nil dependencies before building the graph"],"exampleFix":"# before\nConcurrent.dataflow(2, future_a) { |a, b| a + b }\n# after\nConcurrent.dataflow(Concurrent.future { 2 }, future_a) { |a, b| a + b }","handlingStrategy":"type-guard","validationCode":"inputs = inputs.map { |i| i.is_a?(Concurrent::IVar) ? i : Concurrent.future { i } }\nConcurrent.dataflow(*inputs) { |a, b| a + b }","typeGuard":"def ivar_input?(input)\n  input.is_a?(Concurrent::IVar) # true for Future, Promise, IVar, dataflow results\nend","tryCatchPattern":"begin\n  Concurrent.dataflow(*inputs, &task)\nrescue ArgumentError => e\n  raise unless e.message.start_with?('Not all dependencies are IVars')\n  inputs = inputs.map { |i| i.is_a?(Concurrent::IVar) ? i : Concurrent.future { i } }\n  retry\nend","preventionTips":["Splat dependency arrays: dataflow(*futures), never dataflow(futures)","Wrap constants as Concurrent.future { value } before adding them as inputs","Assert inputs.all? { |i| i.is_a?(Concurrent::IVar) } in specs covering graph construction"],"tags":["ruby","concurrency","dataflow","argument-error","type-mismatch"],"backgroundTag":"invalid-argument-type","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}