{"record":{"id":"66b8d1da9b5a4bef","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-66b8d1","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/promise.rb","lineNumber":350,"sourceCode":"\n      synchronize do\n        child.state = :pending if @state == :pending\n        child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled\n        child.on_reject(@reason) if @state == :rejected\n        @children << child\n      end\n\n      child\n    end\n\n    # Chain onto this promise an action to be undertaken on success\n    # (fulfillment).\n    #\n    # @yield The block to execute\n    #\n    # @return [Promise] self\n    def on_success(&block)\n      raise ArgumentError.new('no block given') unless block_given?\n      self.then(&block)\n    end\n\n    # Chain onto this promise an action to be undertaken on failure\n    # (rejection).\n    #\n    # @yield The block to execute\n    #\n    # @return [Promise] self\n    def rescue(&block)\n      self.then(block)\n    end\n\n    alias_method :catch, :rescue\n    alias_method :on_error, :rescue\n\n    # Yield the successful result to the block that returns a promise. If that\n    # promise is also successful the result is the result of the yielded promise.","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/promise.rb#L332-L368","documentation":"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.","triggerScenarios":"promise.on_success with nothing; promise.on_success(callback) passing a Proc positionally; forwarding from a wrapper that accepts a callback parameter but forgets &.","commonSituations":"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.","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)"],"exampleFix":"# before\nhandler = ->(v) { puts v }\npromise.on_success(handler)\n\n# after\nhandler = ->(v) { puts v }\npromise.on_success(&handler)","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'callback block required' unless block_given?\npromise.on_success { |value| yield(value) }","typeGuard":"->(obj) { obj.respond_to?(:call) } # then on_success(&obj)","tryCatchPattern":"begin\n  promise.on_success(&handler)\nrescue ArgumentError => e\n  raise ArgumentError, 'on_success needs a block' if /no block/.match?(e.message)\n  raise\nend","preventionTips":["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"],"tags":["ruby","concurrency","promise","block-argument","argument-validation"],"backgroundTag":"missing-block-argument","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}