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

  1. Pass the block: promise.on_success { |value| handle(value) }
  2. If the handler is stored, splat it: promise.on_success(&handler)
  3. 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

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.