ruby-concurrency/concurrent-ruby · error · ArgumentError
cannot give arguments and a block
Error message
cannot give arguments and a block
What it means
The copy-on-write observer set's notify_to delivers notifications to a set of observers and accepts either a fixed argument list or a block that recomputes args per observer — passing both is ambiguous and raises ArgumentError. Unlike the copy-on-notify variant this method is private, so it is reached through subclasses of the set, custom Observable implementations, or explicit send(:notify_to, ...).
Source
Thrown at lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb:87
#
# @param [Object] args arguments to be passed to each observer
# @return [CopyOnWriteObserverSet] self
def notify_and_delete_observers(*args, &block)
old = clear_observers_and_return_old
notify_to(old, *args, &block)
self
end
protected
def ns_initialize
@observers = {}
end
private
def notify_to(observers, *args)
raise ArgumentError.new('cannot give arguments and a block') if block_given? && !args.empty?
observers.each do |observer, function|
args = yield if block_given?
observer.send(function, *args)
end
end
def observers
synchronize { @observers }
end
def observers=(new_set)
synchronize { @observers = new_set }
end
def clear_observers_and_return_old
synchronize do
old_observers = @observers
@observers = {}View on GitHub (pinned to 0b88d5ff75)
Solutions
- Pass either positional args or the block, never both: `notify_to(observers, :changed, data)` or `notify_to(observers) { args }`.
- In forwarding code, branch on block_given? before delegating.
Example fix
// before
set.send(:notify_to, observers, :changed, payload) { fresh_payload }
// after
set.send(:notify_to, observers, :changed, payload)
// or
set.send(:notify_to, observers) { fresh_payload } Defensive patterns
Strategy: validation
Validate before calling
if block_given?
set.send(:notify_to, observers) { yield }
else
set.send(:notify_to, observers, *args)
end Try / catch
begin
set.send(:notify_to, observers, :changed, payload) { fresh }
rescue ArgumentError => e
raise unless e.message == 'cannot give arguments and a block'
set.send(:notify_to, observers, :changed, payload)
end Prevention
- notify_to is private on this set — subclass or use send deliberately, and never pass args plus a block together.
- Branch on block_given? before delegating to the private API.
- Prefer the set's public notify methods over reaching into notify_to.
When it happens
Trigger: A subclass of CopyOnWriteObserverSet (or Observable code reusing it) calling `notify_to(observers, :changed, data) { block }`; forwarding wrappers that pass both *args and &block into the private notify_to via send.
Common situations: Custom notification strategies subclassing one of the observer sets; refactoring notify plumbing from the copy-on-notify set into the copy-on-write set without dropping one of the two forms.
Related errors
- cannot give arguments and a block
- cannot provide both an observer and a block
- cannot provide both an observer and a block
- should pass observer as a first argument or block
- should pass observer as a first argument or block
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/129fb646bffd6e1a.
Report an issue: GitHub.