ruby-concurrency/concurrent-ruby · error · ArgumentError
no block given
Error message
no block given
What it means
Concurrent::ReentrantReadWriteLock#with_read_lock executes its block while the current thread holds the (reentrant) shared read lock, releasing it in an ensure clause. As with the plain ReadWriteLock, the block API exists to run a block, so it raises ArgumentError immediately when no block is attached.
Source
Thrown at lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb:127
def initialize
super()
@Counter = AtomicFixnum.new(0) # single integer which represents lock state
@ReadQueue = Synchronization::Lock.new # used to queue waiting readers
@WriteQueue = Synchronization::Lock.new # used to queue waiting writers
@HeldCount = LockLocalVar.new(0) # indicates # of R & W locks held by this thread
end
# Execute a block operation within a read lock.
#
# @yield the task to be performed within the lock.
#
# @return [Object] the result of the block operation.
#
# @raise [ArgumentError] when no block is given.
# @raise [Concurrent::ResourceLimitError] if the maximum number of readers
# is exceeded.
def with_read_lock
raise ArgumentError.new('no block given') unless block_given?
acquire_read_lock
begin
yield
ensure
release_read_lock
end
end
# Execute a block operation within a write lock.
#
# @yield the task to be performed within the lock.
#
# @return [Object] the result of the block operation.
#
# @raise [ArgumentError] when no block is given.
# @raise [Concurrent::ResourceLimitError] if the maximum number of readers
# is exceeded.
def with_write_lockView on GitHub (pinned to 0b88d5ff75)
Solutions
- Pass the read critical section as a block: `lock.with_read_lock { read_all }`.
- For scopeless holding use acquire_read_lock / release_read_lock in begin/ensure (the reentrant counter makes same-thread reacquire safe).
- Forward blocks with &blk in wrappers.
Example fix
// before
lock.with_read_lock
rows = read_all
// after
lock.with_read_lock { read_all } Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, 'read section block required' unless block_given?
lock.with_read_lock { yield } Try / catch
begin
lock.with_read_lock { read_all }
rescue ArgumentError => e
raise unless e.message == 'no block given'
end Prevention
- Use the block API with a block, or acquire_read_lock/release_read_lock with begin/ensure for scopeless holding.
- Rely on the lock's reentrancy instead of nesting different API styles.
- Forward blocks with &blk in wrappers.
When it happens
Trigger: `lock.with_read_lock` with no block; `rwl.with_read_lock(&nil)`; wrapper methods around with_read_lock that fail to forward the block.
Common situations: Migrating code from acquire/release style to block style and leaving a call site bare; wrappers or decorators that accept no block yet call with_read_lock.
Related errors
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/c3b9fb3e98224bcb.
Report an issue: GitHub.