ruby-concurrency/concurrent-ruby · error · ArgumentError
no block given
Error message
no block given
What it means
Concurrent::ReadWriteLock#with_read_lock executes its block while holding the shared read lock and releases it in an ensure clause. The block is the entire critical section, so the method raises ArgumentError immediately when no block is attached.
Source
Thrown at lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb:78
def initialize
super()
@Counter = AtomicFixnum.new(0) # single integer which represents lock state
@Writer = AtomicReference.new(nil) # the thread currently holding the write lock
@ReadLock = Synchronization::Lock.new
@WriteLock = Synchronization::Lock.new
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 { data.retrieve }`.
- If you cannot use a block, use the manual pair acquire_read_lock / release_read_lock wrapped in begin/ensure.
- When wrapping in a helper, forward the block explicitly: `def read(&blk) lock.with_read_lock(&blk) end`.
Example fix
// before
lock.with_read_lock
data.retrieve
// after
lock.with_read_lock { data.retrieve }
// or manual pairing
lock.acquire_read_lock
begin
data.retrieve
ensure
lock.release_read_lock
end 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
- Treat with_read_lock/with_write_lock as block-only APIs; use acquire_/release_ pairs when no block fits.
- Pair every manual acquire_read_lock with an ensure-driven release_read_lock.
- Forward blocks with &blk when wrapping lock calls in helper methods.
When it happens
Trigger: `lock.with_read_lock` with no block; `lock.with_read_lock(&nil)`; helper methods that wrap with_read_lock but forget to forward `yield`/`&blk`.
Common situations: Intending to hold the lock manually across statements and reaching for the block API by mistake (use acquire_read_lock/release_read_lock instead); refactors that moved the block into a conditional branch; builders or DSLs that drop blocks silently.
Related errors
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/23e2ee1abce6f53f.
Report an issue: GitHub.