skip to content

In Ruby 4.0, what do `wrong number of arguments (given 1, expected 2..3)` and `(given 0, expected 1+)` tell you about the method called?

level: middleimportance: should knowfreq 38%

answer

  1. given counts positional arguments
  2. N, N..M or N+
  3. means a rest parameter
  4. top frame is the callee
  5. ; required keyword suffix

basics

~20 s

Given is the number of positional arguments passed; expected is the accepted range. 2..3 means two required plus one optional; 1+ means one required and a rest parameter. The backtrace's top frame is the called method's definition.

solid answer

~40 s

An `ArgumentError` for arity reads `wrong number of arguments (given G, expected E)`. `G` is how many **positional arguments** the call supplied. `E` describes the signature: a single number means exactly that many required parameters, `N..M` means `N` required plus `M - N` optional, and `N+` means `N` required and a **rest parameter**, so no upper bound. When the method also has required keywords, Ruby appends `; required keyword: name`. The **first backtrace line points at the called method's definition**, and the caller that passed the wrong count is the next line down; since Ruby 3.4 those lines read like `in 'AuditLog#log'`. Built-in methods written in C report the same format, such as `"abc".center` giving `(given 0, expected 1..2)`.

code

ruby · 13 lines
ruby
class AuditLog
  def log(level, msg)
    puts "[#{level}] #{msg}"
  end

  def note(msg, level = :info) = log(level, msg)
  def batch(level, *messages) = messages.each { |m| log(level, m) }
end

audit = AuditLog.new
audit.log(:info)        # (given 1, expected 2)
audit.note              # (given 0, expected 1..2)
audit.batch             # (given 0, expected 1+)

go deeper

for a junior

Recall that given is what you passed and expected is what the method accepts, and read 2, 1..2 and 1+ correctly.

for a middle

Explain how minimum and maximum come from required, optional, trailing and rest parameters, and why the top backtrace frame is the callee.

for a senior

Use the message and the second frame to trace signature changes across a codebase quickly, and prefer forwarding with ... in wrappers so counts cannot drift.

for a principal

Plan signature changes to widely used methods so arity breaks surface in tests and deprecation windows rather than as production ArgumentErrors.

## Reading the message When a call supplies the wrong number of positional arguments, Ruby raises `ArgumentError` with a message in one fixed shape: ``` wrong number of arguments (given G, expected E) ``` - **`given G`** is the count of positional arguments at the call, after any call-site splats were expanded. - **`expected E`** summarises the method's positional parameters in one of three forms. | `expected` part | Signature it implies | Example definition | |---|---|---| | `2` | exactly two required | `def log(level, msg)` | | `1..2` | one required, one optional | `def log(msg, level = :info)` | | `2..4` | two required, two optional | `def log(a, b, c = 1, d = 2)` | | `1+` | one required plus a rest parameter | `def log(level, *messages)` | | no error at all | a rest-only method accepts any count | `def log(*messages)` | The message is built from the minimum and maximum counts: the maximum is omitted when it equals the minimum, printed after `..` when finite, and replaced by `+` when a rest parameter makes it unlimited. Trailing required parameters count toward the minimum, so `def wrap(open, *parts, close)` reports `expected 2+`. ## The keyword suffix If the method declares required keyword parameters, the arity message gains a suffix listing them, for example `(given 0, expected 1; required keyword: level)`. The suffix is appended whenever such keywords exist, even when the caller did pass them and only the positional count was wrong, so read it as a reminder of the signature rather than as the cause. Missing or unknown keyword errors have their own messages, which are a separate topic. ## Finding the bad call in the backtrace Ruby raises the error as if from inside the called method, so the **top frame is the callee's definition line** and the **second frame is the caller**: ``` audit_log.rb:2:in 'AuditLog#log': wrong number of arguments (given 1, expected 2) (ArgumentError) from app.rb:7:in '<main>' ``` 1. Read the top line to learn which method and signature were involved. 2. Go one frame down to find the call that passed the wrong count. 3. Compare the call against the `expected` part: too few means a required parameter is missing, too many means the method has no rest parameter to absorb the extra. Since Ruby 3.4, backtraces use single quotes instead of a backtick and show the owning class before the method name, as in `'AuditLog#log'`, which makes the callee easier to identify when several classes define `log`. ## Built-in methods report the same way Core methods implemented in C check their argument counts with the same wording. `"abc".center` with no arguments raises `wrong number of arguments (given 0, expected 1..2)`, because `String#center` takes a width and an optional pad string. Knowing the format lets you infer a C method's signature from the error alone. ## A worked diagnosis Suppose `AuditLog#log(level, msg)` gained a third required parameter, `source`, and a background job still calls `audit.log(:info, "synced")`: 1. The job fails with `wrong number of arguments (given 2, expected 3)`. 2. The top backtrace frame names `'AuditLog#log'` and its definition line, confirming which signature changed. 3. The second frame is the job's call site, the line to update. 4. If the new parameter had been optional, `source = :app`, the message would never appear and old calls would keep working, which is why widening a signature with optionals or keywords is the gentler change. ## Common causes in practice - A method gained a required parameter and some callers were not updated. - An Array was passed where separate arguments were expected; add a splat, `log(*parts)`. - A splat produced more elements than the method accepts. - A wrapper forwarded arguments by hand and dropped or duplicated one; forwarding with `...` avoids that class of mistake.

  • In Ruby, what arity message does `def wrap(open, *parts, close)` produce when called with one argument?
    `wrong number of arguments (given 1, expected 2+)`. Both the leading and the trailing required parameters count toward the minimum of two, and the rest parameter removes the maximum, which Ruby prints as `+`.
  • Why is the first backtrace line of a Ruby arity error inside the called method rather than at the bad call?
    Ruby raises the error from a frame for the callee, so the top line names the method and its definition line. The call that passed the wrong count is the next frame down, which is the line to fix.

saying these in an interview costs you the question

  • given counts the block as one of the arguments.
  • expected 1+ means at least one optional argument.
  • The first backtrace line is always the call that passed the wrong count.
  • 2..3 means the method takes two or three required arguments.
  • A required keyword suffix proves the keyword was missing.