{"record":{"id":"23e2ee1abce6f53f","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-23e2ee","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb","lineNumber":78,"sourceCode":"    def initialize\n      super()\n      @Counter   = AtomicFixnum.new(0)      # single integer which represents lock state\n      @Writer    = AtomicReference.new(nil) # the thread currently holding the write lock\n      @ReadLock  = Synchronization::Lock.new\n      @WriteLock = Synchronization::Lock.new\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":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb#L60-L96","documentation":"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.","triggerScenarios":"`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`.","commonSituations":"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.","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`."],"exampleFix":"// before\nlock.with_read_lock\ndata.retrieve\n\n// after\nlock.with_read_lock { data.retrieve }\n\n// or manual pairing\nlock.acquire_read_lock\nbegin\n  data.retrieve\nensure\n  lock.release_read_lock\nend","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":["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."],"tags":["concurrent-ruby","read-write-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"}