{"record":{"id":"165594be97490927","repo":"ruby-concurrency/concurrent-ruby","slug":"wrong-number-of-arguments-argc-for-arity","errorCode":null,"errorMessage":"wrong number of arguments (#{argc} for #{arity})","messagePattern":"wrong number of arguments \\(#(.+?) for #(.+?)\\)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/async.rb","lineNumber":255,"sourceCode":"    # @raise [ArgumentError] the given `args` do not match the arity of `method`\n    #\n    # @note This check is imperfect because of the way Ruby reports the arity of\n    #   methods with a variable number of arguments. It is possible to determine\n    #   if too few arguments are given but impossible to determine if too many\n    #   arguments are given. This check may also fail to recognize dynamic behavior\n    #   of the object, such as methods simulated with `method_missing`.\n    #\n    # @see http://www.ruby-doc.org/core-2.1.1/Method.html#method-i-arity Method#arity\n    # @see http://ruby-doc.org/core-2.1.0/Object.html#method-i-respond_to-3F Object#respond_to?\n    # @see http://www.ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing BasicObject#method_missing\n    #\n    # @!visibility private\n    def self.validate_argc(obj, method, *args)\n      argc = args.length\n      arity = obj.method(method).arity\n\n      if arity >= 0 && argc != arity\n        raise ArgumentError.new(\"wrong number of arguments (#{argc} for #{arity})\")\n      elsif arity < 0 && (arity = (arity + 1).abs) > argc\n        raise ArgumentError.new(\"wrong number of arguments (#{argc} for #{arity}..*)\")\n      end\n    end\n\n    # @!visibility private\n    def self.included(base)\n      base.singleton_class.send(:alias_method, :original_new, :new)\n      base.extend(ClassMethods)\n      super(base)\n    end\n\n    # @!visibility private\n    module ClassMethods\n      def new(*args, &block)\n        obj = original_new(*args, &block)\n        obj.send(:init_synchronization)\n        obj","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/async.rb#L237-L273","documentation":"Concurrent::Async gives any object async/await proxies that schedule method calls on a background thread. A native Ruby arity failure would be raised inside that delegated execution where the caller cannot see it, so Async.validate_argc re-checks the argument count against Method#arity synchronously, before the call is scheduled. This variant fires when the target method has a fixed arity and the number of arguments passed differs from it.","triggerScenarios":"Calling a delegated method with the wrong count of arguments: `string = Concurrent::Async.wrap('ab')` then `string.async.upcase(1)` (upcase takes 0 args); `obj.await.foo(1)` when the method is `def foo(a, b)`; splatting a dynamically built array `obj.async.foo(*args)` where args.size does not equal the method's fixed arity.","commonSituations":"Refactoring a method signature (adding or removing a parameter) without updating async/await call sites; forwarding *args collected elsewhere that have the wrong length; test stubs whose arity differs from the real object; Ruby 2-to-3 keyword-argument changes shifting effective arities.","solutions":["Match the argument count at the call site to the method definition (count the required parameters).","Before dispatching dynamic args, check `obj.method(:foo).arity` and only call `proxy.async.foo(*args)` when the counts agree.","If the target legitimately accepts variable input, give the method an `*args` parameter so its arity is negative and only a minimum is enforced.","Wrap the async call in begin/rescue ArgumentError — validate_argc runs on the calling thread, so the mismatch is catchable at the call site."],"exampleFix":"// before (def transfer(from, to, amount))\nclient.async.transfer(from_acct, to_acct)\n\n// after\nclient.async.transfer(from_acct, to_acct, 125_00)","handlingStrategy":"validation","validationCode":"m = payment_gateway.method(:transfer)\nargs = [from, to, amount]\nvalid = m.arity >= 0 ? m.arity == args.size : args.size >= (m.arity + 1).abs\nproxy.async.transfer(*args) if valid","typeGuard":"def arity_matches?(obj, meth, *args)\n  a = obj.method(meth).arity\n  a >= 0 ? args.size == a : args.size >= (a + 1).abs\nend","tryCatchPattern":"begin\n  proxy.async.transfer(from, to)\nrescue ArgumentError => e\n  raise unless e.message.start_with?('wrong number of arguments')\n  logger.error(\"arity mismatch before dispatch: #{e.message}\")\nend","preventionTips":["Re-run the test suite against async/await call sites whenever a method signature changes.","Never splat unvalidated arrays into async calls; check the length against Method#arity first.","Remember the check runs on the caller thread, so unlike errors inside the delegated call, this ArgumentError can be rescued locally."],"tags":["concurrent-ruby","async","arity","argumenterror"],"backgroundTag":"wrong-number-of-arguments","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}