Skip to content

Rust Error E0057: This Function Takes N Arguments but M Were Supplied (Closures)

E0057 means you called a closure with the wrong number of arguments: too few or too many. It’s the closure version of E0061, and the message reads almost the same. The fix is usually quick: look at the closure’s |...| and pass one value per parameter. This page also covers two close relatives you’ll meet with iterators, E0593 and E0631, because they come from the same mix-up. For the other errors in this series, see Rust compiler errors.

error[E0057]: this function takes 2 arguments but 1 argument was supplied
--> src/main.rs:3:17
|
3 | let total = add(1); // ❌ add wants two numbers
| ^^^--- argument #2 of type `i32` is missing
|
note: closure defined here
--> src/main.rs:2:15
|
2 | let add = |a: i32, b: i32| a + b;
| ^^^^^^^^^^^^^^^^
help: provide the argument
|
3 | let total = add(1, /* i32 */); // ❌ add wants two numbers
| +++++++++++

This is the program that produces it:

fn main() {
let add = |a: i32, b: i32| a + b;
let total = add(1); // ❌ add wants two numbers
println!("{total}");
}

Too many arguments gives the same code, with an “unexpected argument” label and a “remove the extra argument” help:

error[E0057]: this function takes 1 argument but 2 arguments were supplied
--> src/main.rs:3:5
|
3 | greet("Ferris", "Corro");
| ^^^^^ ------- unexpected argument #2 of type `&'static str`
|
note: closure defined here

Read the message like the one for functions: the first line counts (the closure takes 2, you gave 1), the label under your call names the missing or extra argument, and help: shows where it goes. /* i32 */ is only a placeholder comment telling you the type. Put a real value there.

E0057 or E0061? The first line is the same. The note: tells them apart:

  • closure defined here: you called a closure. That’s E0057.
  • callable defined here: you called a generic f with a bound like F: Fn(i32). Also E0057.
  • function defined here: a normal fn, a method, or a function pointer (let f: fn(i32, i32) -> i32 = add;). That’s E0061.

Either way, the fix is the same: match the call to the parameter list.

A closure’s parameter list is as fixed as a function’s. |a: i32, b: i32| takes exactly two i32s, every time. There are no default arguments and no “pass fewer if you like”. Even when you leave out the types, rustc works them out from the closure’s body and its first use, and from then on they’re locked in.

Under the hood, a closure implements one of the Fn traits with a fixed list of argument types, like Fn(i32, i32) -> i32. The compiler checks every call against that list, so a call with the wrong count never reaches your running program. How closures and their parameters work is covered in Closures and Closure traits.

Fix 1: Match the call to the closure’s parameters

Section titled “Fix 1: Match the call to the closure’s parameters”

Choose this almost every time. Jump to the note: location, count the parameters between the pipes |...|, and pass one value for each. If you have more values than parameters, call the closure more than once:

fn main() {
let add = |a: i32, b: i32| a + b;
let greet = |name: &str| println!("Hello, {name}!");
let total = add(1, 2);
println!("{total}");
greet("Ferris");
greet("Corro"); // one call per name
}

Output:

3
Hello, Ferris!
Hello, Corro!
▶ Try it Yourself

If the closure really should take a different number of values, change the closure instead. That’s fine too, as long as every call agrees with it.

Choose this when tuples are involved. |(name, score)| and |name, score| look alike, but they are different closures. The first takes one argument, a tuple, and unpacks it. The second takes two arguments.

Calling a tuple closure with two values gives E0057, and rustc suggests adding the parentheses:

error[E0057]: function takes 1 argument but 2 arguments were supplied
--> src/main.rs:3:5
|
3 | show("Ferris", 90);
| ^^^^
|
note: closure parameter defined here
help: wrap these arguments in parentheses to construct a tuple
|
3 | show(("Ferris", 90));
| + +

The opposite mistake happens all the time with iterators. zip, enumerate and map iteration hand your closure one tuple per item. Writing .map(|name, score| ...) gives a different code, E0593:

error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
--> src/main.rs:7:10
|
7 | .map(|name, score| format!("{name}: {score}"))
| ^^^ ------------- takes 2 distinct arguments
| |
| expected closure that takes a single 2-tuple as argument
|
help: change the closure to accept a tuple instead of individual arguments
|
7 - .map(|name, score| format!("{name}: {score}"))
7 + .map(|(name, score)| format!("{name}: {score}"))

Both have the same fix: put the parentheses where the tuple is.

fn main() {
let names = vec!["Ferris", "Corro"];
let scores = vec![90, 75];
// zip gives one (name, score) tuple per item: unpack it in the parameter list
let lines: Vec<String> = names
.iter()
.zip(scores.iter())
.map(|(name, score)| format!("{name}: {score}"))
.collect();
println!("{:?}", lines);
// a closure that takes a tuple is called with one tuple
let show = |(name, score): (&str, i32)| println!("{name} scored {score}");
show(("Ferris", 90));
}

Output:

["Ferris: 90", "Corro: 75"]
Ferris scored 90
▶ Try it Yourself

The same goes for .enumerate().map(|(i, item)| ...) and map.iter().for_each(|(key, value)| ...). See Iterators and Tuples.

Choose this when you pass a function or closure to another function (a “higher-order function”) and the parameter counts don’t line up. Here apply wants something that takes one i32, but add takes two. That gives E0593 again:

error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
--> src/main.rs:10:26
|
5 | fn add(a: i32, b: i32) -> i32 {
| ----------------------------- takes 2 arguments
...
10 | println!("{}", apply(add, 5));
| ----- ^^^ expected function that takes 1 argument
| |
| required by a bound introduced by this call

Don’t change add. Wrap it in a small closure that has the shape apply expects and fills in the missing value itself:

fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let bonus = 10;
// takes 1 argument, calls add with 2
println!("{}", apply(|x| add(x, bonus), 5));
// takes 1 tuple, calls add with its two parts
let pairs = vec![(1, 2), (3, 4)];
let sums: Vec<i32> = pairs.into_iter().map(|(a, b)| add(a, b)).collect();
println!("{:?}", sums);
}

Output:

15
[3, 7]
▶ Try it Yourself

The wrapper borrows bonus from the surrounding code, which is exactly what closures are good at. Passing a function by name (apply(double, 5)) works only when its parameters already match. See Closure traits.

Inside a generic function. fn call_twice<F: Fn(i32)>(f: F) that calls f(2, 3) gives E0057 with note: callable defined here, pointing at Fn(i32). The bound is the parameter list. Fix: call f(2), or change the bound to Fn(i32, i32) if you really need two values (then every caller’s closure must take two).

Boxed closures. let f: Box<dyn Fn(i32, i32) -> i32> = Box::new(|a, b| a + b); then f(1) gives E0057 with note: implementation defined here. Fix: pass both values, f(1, 2).

Sorting. v.sort_by(|a| a.cmp(a)) gives E0593, “closure is expected to take 2 arguments, but it takes 1 argument”. sort_by compares two items at a time. Fix: v.sort_by(|a, b| a.cmp(b)). See Sorting.

Right count, wrong type. nums.iter().map(|x: i32| x * 2) gives E0631, “type mismatch in closure arguments”, because .iter() hands out &i32. rustc’s help suggests |x: &i32|. Simplest fix: drop the annotation, |x| x * 2.

Unpacking something that isn’t a tuple. v.iter().map(|(a, b)| a + b) on a plain Vec<i32> gives E0308, “expected integer, found (_, _)”. Fix: only use |(a, b)| when the items really are pairs.

Quick check

1. let double = |x: i32| x * 2; is called as double(2, 3). What does rustc report?

2. names.iter().zip(ages.iter()).map(|n, a| ...) doesn't compile. What is the fix?

3. Both E0057 and E0061 say this function takes 2 arguments but 1 argument was supplied. How can you tell you called a closure?

Score: 0 / 3