ruby-concurrency/concurrent-ruby · error · ArgumentError
provide only a value or a block
Error message
provide only a value or a block
What it means
An IVar is a write-once container that starts pending and is completed exactly once. Its constructor accepts either an initial value or a block that computes the value — never both. Passing a value and a block simultaneously raises ArgumentError 'provide only a value or a block'.
Source
Thrown at lib/concurrent-ruby/concurrent/ivar.rb:64
# 2. For recent application:
# [DataDrivenFuture in Habanero Java from Rice](http://www.cs.rice.edu/~vs3/hjlib/doc/edu/rice/hj/api/HjDataDrivenFuture.html).
class IVar < Synchronization::LockableObject
include Concern::Obligation
include Concern::Observable
# Create a new `IVar` in the `:pending` state with the (optional) initial value.
#
# @param [Object] value the initial value
# @param [Hash] opts the options to create a message with
# @option opts [String] :dup_on_deref (false) call `#dup` before returning
# the data
# @option opts [String] :freeze_on_deref (false) call `#freeze` before
# returning the data
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
# the internal value and returning the value returned from the proc
def initialize(value = NULL, opts = {}, &block)
if value != NULL && block_given?
raise ArgumentError.new('provide only a value or a block')
end
super(&nil)
synchronize { ns_initialize(value, opts, &block) }
end
# Add an observer on this object that will receive notification on update.
#
# Upon completion the `IVar` will notify all observers in a thread-safe way.
# The `func` method of the observer will be called with three arguments: the
# `Time` at which the `Future` completed the asynchronous operation, the
# final `value` (or `nil` on rejection), and the final `reason` (or `nil` on
# fulfillment).
#
# @param [Object] observer the object that will be notified of changes
# @param [Symbol] func symbol naming the method to call when this
# `Observable` has changes`
def add_observer(observer = nil, func = :update, &block)
raise ArgumentError.new('cannot provide both an observer and a block') if observer && blockView on GitHub (pinned to 0b88d5ff75)
Solutions
- Choose one: Concurrent::IVar.new(42) for a known value, or Concurrent::IVar.new { compute } for a deferred one
- If you need options, put them in the hash after the value/default: Concurrent::IVar.new { compute } is equivalent to passing opts in many examples — keep the value slot untouched
- If both a value and computation exist, decide precedence in your own code and pass only the winner
Example fix
# before
ivar = Concurrent::IVar.new(42) { expensive_default }
# after
ivar = Concurrent::IVar.new(42)
# or, when the value must be computed:
ivar = Concurrent::IVar.new { expensive_default } Defensive patterns
Strategy: validation
Validate before calling
def build_ivar(value = nil, has_value: false, &block) raise ArgumentError, 'value or block, not both' if has_value && block has_value ? Concurrent::IVar.new(value) : Concurrent::IVar.new(&block) end
Try / catch
begin
Concurrent::IVar.new(value) { compute }
rescue ArgumentError => e
raise ArgumentError, 'pick value or block for IVar' if /value or a block/.match?(e.message)
raise
end Prevention
- Pick one initialization style (value or block) per codebase and stick to it
- Keep constructor positional slot for the value only; everything else goes in the opts hash
- Add a lint/review check for IVar.new calls that have both an argument and a brace block
When it happens
Trigger: Concurrent::IVar.new(42) { compute } — value plus block; copying an initialization pattern from IVar#set (which also takes value-or-block) into the constructor while keeping both; passing a value that was meant to be an options hash entry.
Common situations: Refactors where a computed default was replaced by a literal but the block stayed; mixing :executor-style option hashes with the positional value slot; subclasses calling super with both.
Related errors
- cannot provide both an observer and a block
- must set with either a value or a block
- `min_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}
- `min_threads` cannot be more than `max_threads`
- no block given
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/69332f28a7899de2.
Report an issue: GitHub.