Skip to content

Rust Error E0061: This Function Takes N Arguments but M Were Supplied

E0061 means you called a function with the wrong number of arguments: too few or too many. It’s one of the friendliest errors in Rust, because rustc tells you exactly which argument is missing or extra, and what type it should be. It shows up a lot for people coming from Python, JavaScript or C#, where default arguments and overloading are normal. Rust has neither, and this page shows what to do instead. For the other errors in this series, see Rust compiler errors.

error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> src/main.rs:6:5
|
6 | greet("Ferris"); // ❌ greet wants two arguments
| ^^^^^---------- argument #2 of type `&str` is missing
|
note: function defined here
--> src/main.rs:1:4
|
1 | fn greet(name: &str, greeting: &str) {
| ^^^^^ --------------
help: provide the argument
|
6 | greet("Ferris", /* &str */); // ❌ greet wants two arguments
| ++++++++++++

This is the program that produces it:

fn greet(name: &str, greeting: &str) {
println!("{greeting}, {name}!");
}
fn main() {
greet("Ferris"); // ❌ greet wants two arguments
}

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

error[E0061]: this function takes 2 arguments but 3 arguments were supplied
--> src/main.rs:6:13
|
6 | let a = area(3, 4, 5);
| ^^^^ - unexpected argument #3 of type `{integer}`

For a method called with a dot, the first line says “this method takes…” instead. For a tuple struct like Rgb(255, 0) it says “this struct takes 3 arguments”. It’s the same error each time.

The message has three parts, and each one helps:

  1. The first line counts: the function wants 2 arguments, you gave 1.
  2. The label under your call names the problem: “argument #2 of type &str is missing”.
  3. The note: jumps to the function’s definition and underlines the parameter you left out, greeting: &str.

The help: line shows where the argument goes. /* &str */ is only a placeholder that tells you the type; it’s a comment, so pasting it in as-is won’t compile. Put a real value there, like "Hello".

It’s like a coffee machine that needs both a cup and a coin. Putting in only the coin doesn’t get you half a coffee. It just doesn’t start.

In Rust, a function’s signature is an exact contract: these parameters, in this order, with these types. Every call must match it. There are no default arguments (greeting = "Hello"), no overloading (two functions called greet with different parameters), and no functions that take “any number” of arguments. Trying to write a default gives error: parameter defaults are not supported, and a second greet gives E0428, “the name greet is defined multiple times”.

That sounds strict, but it pays off. When you read greet(name, greeting), you know exactly which function runs and what it receives. When you add a parameter to a function, the compiler lists every call that needs updating, so none get missed. (Things like println! that do take any number of values are macros, which is what the ! means. See Macros.)

How parameters work is covered in Functions.

Fix 1: Pass exactly what the signature asks for

Section titled “Fix 1: Pass exactly what the signature asks for”

Choose this almost every time. Open the note: location, read the parameter list, and pass one value per parameter, in order:

fn greet(name: &str, greeting: &str) {
println!("{greeting}, {name}!");
}
fn main() {
greet("Ferris", "Hello");
greet("Corro", "Good morning");
}

Output:

Hello, Ferris!
Good morning, Corro!
▶ Try it Yourself

If you just changed the function and now every call is broken, that’s the compiler helping you: fix each call it lists, or ask yourself whether the new parameter should really be optional (Fix 3).

Choose this when the function has a self parameter. A method is normally called as value.method(args). The value before the dot fills self, so you don’t count it. If you write Type::method(args) instead, nothing fills self:

error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> src/main.rs:13:5
|
13 | Account::deposit(50);
| ^^^^^^^^^^^^^^^^ -- argument #1 of type `&mut Account` is missing
|
help: provide the argument
|
13 | Account::deposit(/* &mut Account */, 50);
| +++++++++++++++++++

Notice the counting. Called as Account::deposit(...), rustc says the function takes 2 arguments, because &mut self counts. Called as acc.deposit(), it says the method takes 1 argument, because the dot already supplies self. Both forms work once every argument is there:

struct Account {
balance: i64,
}
impl Account {
fn deposit(&mut self, amount: i64) {
self.balance += amount;
}
}
fn main() {
let mut acc = Account { balance: 0 };
acc.deposit(50); // the usual way
Account::deposit(&mut acc, 25); // the same call, written out
println!("Balance: {}", acc.balance);
}

Output:

Balance: 75
▶ Try it Yourself

Use the dot form in everyday code. Type::method(&x, a) is useful when you need to pass the method itself somewhere, like team.iter().map(Player::label) (example). If a function has no self at all (like new), it can only be called as Type::function(...). See Structs and E0424.

Fix 3: Use Option<T> for an argument that is sometimes not needed

Section titled “Fix 3: Use Option<T> for an argument that is sometimes not needed”

Choose this when one argument usually has a sensible default. Make it an Option, pass None for “use the default”, and fill it in with unwrap_or:

fn connect(host: &str, port: u16, timeout_secs: Option<u64>) {
let timeout = timeout_secs.unwrap_or(30);
println!("Connecting to {host}:{port} (timeout {timeout}s)");
}
fn main() {
connect("localhost", 8080, None);
connect("example.com", 443, Some(5));
}

Output:

Connecting to localhost:8080 (timeout 30s)
Connecting to example.com:443 (timeout 5s)
▶ Try it Yourself

To be honest: callers still write the argument, None. Rust prefers that, because the call shows that a default is being used. If you’d rather not write it at all, make two functions with clear names instead, like connect(host, port) that calls connect_with_timeout(host, port, 30). That’s the usual Rust answer to overloading. See Option.

Choose this when a function has many settings and most callers only change one or two. Put the settings in a struct, implement Default, and let callers fill in only what they need with ..Default::default():

struct ServerConfig {
host: String,
port: u16,
timeout_secs: u64,
verbose: bool,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
host: String::from("localhost"),
port: 8080,
timeout_secs: 30,
verbose: false,
}
}
}
fn start(config: ServerConfig) {
println!(
"Listening on {}:{} (timeout {}s, verbose: {})",
config.host, config.port, config.timeout_secs, config.verbose
);
}
fn main() {
start(ServerConfig::default());
start(ServerConfig { port: 3000, verbose: true, ..Default::default() });
}

Output:

Listening on localhost:8080 (timeout 30s, verbose: false)
Listening on localhost:3000 (timeout 30s, verbose: true)
▶ Try it Yourself

This also gives you something like named arguments: port: 3000 says what the number means. If every field’s default is the type’s own default (0, false, empty string), #[derive(Default)] writes the impl for you. For bigger APIs, the builder pattern (Server::builder().port(3000).build()) is the next step up. See Structs and Design patterns.

After adding a parameter. You give fn save(path: &str) a second parameter, and every old save("notes.txt") call breaks with E0061. Fix: update each call the compiler lists, or use Fix 3 or Fix 4 if the new value is usually the same.

Standard library methods. names.push("Cy", "Di") gives “this method takes 1 argument but 2 arguments were supplied”. push adds one item. Fix: call it twice, or use names.extend(["Cy", "Di"]). See Vectors.

Tuple structs. struct Rgb(u8, u8, u8); then Rgb(255, 0) gives “this struct takes 3 arguments but 2 arguments were supplied”. Fix: give every field, Rgb(255, 0, 0).

Habits from other languages. Python’s greet("Ferris", greeting="Hi") isn’t Rust syntax. Writing greet(greeting = "Hi") doesn’t name an argument; rustc reads it as an assignment to a variable called greeting and also reports E0425. Fix: pass values by position, or use a config struct (Fix 4).

Closures. Calling add(1) when add is |a: i32, b: i32| a + b gives the same message, but under code E0057 (the closure version). The fix is the same: pass both values.

  • E0308: the number of arguments is right, but one has the wrong type, often because two were swapped.
  • E0424: self used in a function without a self parameter, the other side of method vs. associated function.
  • E0599: no method with that name exists, for example calling an associated function like new with a dot.
  • E0425: cannot find a value, which can appear next to E0061 when you try named arguments.
  • All compiler errors: the full list of error pages. Also related: E0057 (closure called with the wrong number of arguments) and E0428 (a function defined twice, when trying to overload), which has no page of its own.

Quick check

1. fn area(w: u32, h: u32) -> u32 is called as area(5). What does rustc report?

2. A method is fn deposit(&mut self, amount: i64). Which call is correct?

3. You want a timeout argument that most callers don't care about. What is a common Rust approach?

Score: 0 / 3