{"record":{"id":"d83d7bab61150c38","repo":"ruby-concurrency/concurrent-ruby","slug":"cannot-provide-both-an-observer-and-a-block-d83d7b","errorCode":null,"errorMessage":"cannot provide both an observer and a block","messagePattern":"cannot provide both an observer and a block","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/ivar.rb","lineNumber":82,"sourceCode":"        raise ArgumentError.new('provide only a value or a block')\n      end\n      super(&nil)\n      synchronize { ns_initialize(value, opts, &block) }\n    end\n\n    # Add an observer on this object that will receive notification on update.\n    #\n    # Upon completion the `IVar` will notify all observers in a thread-safe way.\n    # The `func` method of the observer will be called with three arguments: the\n    # `Time` at which the `Future` completed the asynchronous operation, the\n    # final `value` (or `nil` on rejection), and the final `reason` (or `nil` on\n    # fulfillment).\n    #\n    # @param [Object] observer the object that will be notified of changes\n    # @param [Symbol] func symbol naming the method to call when this\n    #   `Observable` has changes`\n    def add_observer(observer = nil, func = :update, &block)\n      raise ArgumentError.new('cannot provide both an observer and a block') if observer && block\n      direct_notification = false\n\n      if block\n        observer = block\n        func = :call\n      end\n\n      synchronize do\n        if event.set?\n          direct_notification = true\n        else\n          observers.add_observer(observer, func)\n        end\n      end\n\n      observer.send(func, Time.now, self.value, reason) if direct_notification\n      observer\n    end","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/ivar.rb#L64-L100","documentation":"IVar#add_observer lets you register a callback for completion: either an observer object plus method symbol, or a bare block. Supplying both an observer object and a block is ambiguous — the library cannot tell which callback to invoke — so it raises ArgumentError 'cannot provide both an observer and a block'.","triggerScenarios":"ivar.add_observer(listener, :update) { |v| ... } — object plus block; pasting observer-object sample code and adding a block convenience on top; adapters that always pass an observer and also forward any block.","commonSituations":"Migrating from observer-object style to block style (or vice versa) and leaving both call shapes in place; observer frameworks that wrap user callbacks in objects while the caller also supplies a block.","solutions":["Use the observer-object form: ivar.add_observer(listener, :update)","Or use the block form only: ivar.add_observer { |time, value, reason| handle(value) }","In adapter code, pick one shape at the boundary and strip the other before calling add_observer"],"exampleFix":"# before\nivar.add_observer(listener, :update) { |v| puts v }\n\n# after\nivar.add_observer(listener, :update)\n# or\nivar.add_observer { |time, value, reason| puts value }","handlingStrategy":"validation","validationCode":"def subscribe(ivar, observer = nil, func = :update, &block)\n  raise ArgumentError, 'observer or block, not both' if observer && block\n  block ? ivar.add_observer(&block) : ivar.add_observer(observer, func)\nend","typeGuard":null,"tryCatchPattern":"begin\n  ivar.add_observer(observer, :update)\nrescue ArgumentError => e\n  raise if /observer and a block/.match?(e.message) === false\n  # strip one of the two callback shapes and retry once\n  ivar.add_observer(observer, :update)\nend","preventionTips":["Choose one callback style (object or block) for observer registration across the project","In adapter layers, normalize user callbacks to a single shape before touching the IVar","Cover observer registration in unit tests with both styles, separately"],"tags":["ruby","concurrency","observer-pattern","ivar","argument-validation"],"backgroundTag":"mutually-exclusive-arguments","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}