{"record":{"id":"c3b9fb3e98224bcb","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-c3b9fb","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb","lineNumber":127,"sourceCode":"    def initialize\n      super()\n      @Counter    = AtomicFixnum.new(0)       # single integer which represents lock state\n      @ReadQueue  = Synchronization::Lock.new # used to queue waiting readers\n      @WriteQueue = Synchronization::Lock.new # used to queue waiting writers\n      @HeldCount  = LockLocalVar.new(0) # indicates # of R & W locks held by this thread\n    end\n\n    # Execute a block operation within a read lock.\n    #\n    # @yield the task to be performed within the lock.\n    #\n    # @return [Object] the result of the block operation.\n    #\n    # @raise [ArgumentError] when no block is given.\n    # @raise [Concurrent::ResourceLimitError] if the maximum number of readers\n    #   is exceeded.\n    def with_read_lock\n      raise ArgumentError.new('no block given') unless block_given?\n      acquire_read_lock\n      begin\n        yield\n      ensure\n        release_read_lock\n      end\n    end\n\n    # Execute a block operation within a write lock.\n    #\n    # @yield the task to be performed within the lock.\n    #\n    # @return [Object] the result of the block operation.\n    #\n    # @raise [ArgumentError] when no block is given.\n    # @raise [Concurrent::ResourceLimitError] if the maximum number of readers\n    #   is exceeded.\n    def with_write_lock","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb#L109-L145","documentation":"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.","triggerScenarios":"`lock.with_read_lock` with no block; `rwl.with_read_lock(&nil)`; wrapper methods around with_read_lock that fail to forward the block.","commonSituations":"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.","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."],"exampleFix":"// before\nlock.with_read_lock\nrows = read_all\n\n// after\nlock.with_read_lock { read_all }","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'read section block required' unless block_given?\nlock.with_read_lock { yield }","typeGuard":null,"tryCatchPattern":"begin\n  lock.with_read_lock { read_all }\nrescue ArgumentError => e\n  raise unless e.message == 'no block given'\nend","preventionTips":["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."],"tags":["concurrent-ruby","reentrant-lock","block","argumenterror"],"backgroundTag":"no-block-given","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}