ruby-concurrency/concurrent-ruby · error · ArgumentError
no block given
Error message
no block given
What it means
Promise#on_success registers a callback to run when the promise fulfills; it is a thin wrapper over then and requires the callback as a block. Calling it without a block raises ArgumentError 'no block given' immediately — no callback is registered and the chain is unchanged.
Source
Thrown at lib/concurrent-ruby/concurrent/promise.rb:350
synchronize do
child.state = :pending if @state == :pending
child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled
child.on_reject(@reason) if @state == :rejected
@children << child
end
child
end
# Chain onto this promise an action to be undertaken on success
# (fulfillment).
#
# @yield The block to execute
#
# @return [Promise] self
def on_success(&block)
raise ArgumentError.new('no block given') unless block_given?
self.then(&block)
end
# Chain onto this promise an action to be undertaken on failure
# (rejection).
#
# @yield The block to execute
#
# @return [Promise] self
def rescue(&block)
self.then(block)
end
alias_method :catch, :rescue
alias_method :on_error, :rescue
# Yield the successful result to the block that returns a promise. If that
# promise is also successful the result is the result of the yielded promise.View on GitHub (pinned to 0b88d5ff75)
Solutions
- Pass the block: promise.on_success { |value| handle(value) }
- If the handler is stored, splat it: promise.on_success(&handler)
- For failure handling use promise.rescue { |reason| ... } (also block-based)
Example fix
# before
handler = ->(v) { puts v }
promise.on_success(handler)
# after
handler = ->(v) { puts v }
promise.on_success(&handler) Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, 'callback block required' unless block_given?
promise.on_success { |value| yield(value) } Type guard
->(obj) { obj.respond_to?(:call) } # then on_success(&obj) Try / catch
begin promise.on_success(&handler) rescue ArgumentError => e raise ArgumentError, 'on_success needs a block' if /no block/.match?(e.message) raise end
Prevention
- Pass stored handlers as blocks with &
- Pair on_success with rescue for rejection handling so outcomes are both covered
- Forward blocks explicitly (&block) through any wrapper DSL around promises
When it happens
Trigger: promise.on_success with nothing; promise.on_success(callback) passing a Proc positionally; forwarding from a wrapper that accepts a callback parameter but forgets &.
Common situations: Event-style code migrating to promises where handlers are stored procs; partially written chains left in code after an edit; wrapper DSLs that pass callbacks as named arguments.
Related errors
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/66b8d1da9b5a4bef.
Report an issue: GitHub.