How to fix Rust E0061 this function takes N arguments but M were supplied

Fix Rust E0061 by ensuring the number of arguments in your function call matches the number of parameters defined in the function signature.

When the contract breaks

You are refactoring a helper function. You decide the function needs a timeout parameter. You add timeout: Duration to the definition. You update the call in main. You hit compile. The build fails with E0061. You missed a call site in the error handler. Or you are calling a library function and the documentation shows fn connect(host, port), but you only have the host. The compiler rejects the call.

Error E0061 is the compiler enforcing the function contract. The signature defines exactly how many arguments a function accepts. The call site must supply that exact number. Mismatch the count, and the code does not compile. This error protects you from undefined behavior. In languages without this check, calling a function with the wrong number of arguments misaligns the stack, corrupts memory, or crashes at runtime. Rust catches the mistake immediately.

The function signature is a type

In Rust, the arity of a function is part of its type. A function that takes two integers is a different type than a function that takes one. The type system includes the parameter count. This matters when you pass functions as arguments, store them in variables, or return them from other functions.

Consider a function pointer type. fn(i32) -> i32 describes a function taking one integer and returning one integer. fn(i32, i32) -> i32 describes a function taking two integers. These types are incompatible. If you try to assign a two-argument function to a variable expecting a one-argument function, the compiler rejects it. E0061 often appears in this context when the call site provides a closure or function with the wrong arity for the expected type.

The compiler validates the argument count against the parameter count before checking types. If the count is wrong, E0061 fires. You will not see a type error for an extra argument because the compiler rejects the call structure first. This ordering saves time. It tells you the shape of the call is wrong before it analyzes the contents.

Minimal example

The error message is direct. It names the function, the expected count, and the supplied count. It points to the call site and the definition.

/// Calculates the area of a rectangle.
/// Requires width and height.
fn area(width: f64, height: f64) -> f64 {
    width * height
}

fn main() {
    // Correct: two arguments match the two parameters.
    let rect = area(10.0, 5.0);
    println!("Area: {}", rect);

    // Incorrect: E0061. One argument supplied, two expected.
    // The compiler stops here. The call is ill-formed.
    // let square = area(10.0);
}

The compiler output highlights the call area(10.0). It says this function takes 2 arguments but 1 was supplied. It also points to the definition of area. Use both pointers. The definition is the source of truth. The call site is where the fix happens.

What the compiler checks

The compiler performs a structural check on the call expression. It parses the arguments inside the parentheses. It counts them. It compares the count to the parameter list in the function signature. The check is syntactic and semantic. It handles named arguments in struct initialization, but function calls in Rust do not support named arguments. You must provide positional arguments in the exact order defined.

This strictness prevents ambiguity. In languages with named arguments, you can swap the order and the code still works. Rust requires the order to match. If you swap arguments, you might get E0061 if the types differ and the compiler tries to match them, or you might get E0308 (mismatched types) if the count matches but the types are wrong. E0061 is purely about count.

The error also catches missing arguments in variadic contexts, though Rust has limited support for variadic functions. extern "C" functions can be variadic, but calling them requires unsafe and careful handling. Even there, the fixed prefix of arguments must match. If you call a variadic function with fewer arguments than the fixed prefix requires, E0061 fires.

Realistic scenario: Refactoring drift

Refactoring is the most common trigger for E0061. You change a function signature to add a feature. You update some call sites. You miss others. The compiler finds the missed sites. This is a feature. It forces you to update all call sites.

Consider a logging function. You start with log(message: &str). You add a level parameter: log(level: LogLevel, message: &str). You update the main loop. You forget the error handler. The error handler calls log("Connection failed"). E0061 catches this.

#[derive(Debug, Clone, Copy)]
enum LogLevel {
    Info,
    Error,
}

/// Logs a message with a severity level.
/// The level determines output formatting.
fn log(level: LogLevel, message: &str) {
    match level {
        LogLevel::Info => println!("[INFO] {}", message),
        LogLevel::Error => eprintln!("[ERROR] {}", message),
    }
}

fn main() {
    // Updated call site: two arguments.
    log(LogLevel::Info, "Starting application");

    // Missed call site: E0061. One argument supplied, two expected.
    // log("Connection failed");
}

The fix is to update the call site. log(LogLevel::Error, "Connection failed"). But the deeper fix is to use refactoring tools. IDEs and editors with Rust support provide "Find All References" and "Refactor" commands. These tools update all call sites automatically. Never edit function signatures manually across multiple files. Manual edits invite E0061. Use the tooling. The compiler is your safety net, but the tools prevent the net from needing to catch you.

Pitfalls and edge cases

E0061 appears in subtle ways beyond simple function calls. Recognizing these patterns saves debugging time.

Closures and trait bounds. Closures have types that include their arity. If you pass a closure to a function expecting a different arity, E0061 fires. The error might point to the closure definition or the call site, depending on how the compiler resolves the types.

/// Applies a transformation to a value.
/// Expects a closure taking one argument.
fn apply<F, T, U>(f: F, value: T) -> U
where
    F: FnOnce(T) -> U,
{
    f(value)
}

fn main() {
    // Correct: closure takes one argument.
    let result = apply(|x| x * 2, 5);

    // Incorrect: E0061. Closure takes two arguments, but `apply` expects one.
    // The compiler sees the closure type does not match the bound.
    // let bad = apply(|x, y| x + y, 5);
}

Macros and expansion. Macros expand to code. If a macro expands to a function call with the wrong number of arguments, E0061 fires on the expansion. The error message might point to the macro call site, but the real issue is inside the macro definition. Use cargo expand to see the generated code. Check the macro for missing arguments in the expansion.

Struct initialization vs function calls. Rust supports .. syntax for struct initialization to copy fields from another instance. This syntax does not work for function calls. If you try func(..), you get a syntax error or E0061 depending on the context. The .. syntax is reserved for structs and enums. Function calls require explicit arguments.

Convention aside. The community convention is to keep function argument counts low. Functions with many arguments are hard to call correctly. E0061 becomes more likely as the count increases. Clippy warns about too_many_arguments. If you see this warning, refactor. Group arguments into structs or use a builder pattern. This reduces the chance of arity errors and improves readability.

Convention aside. Function names should describe the action. Parameter names should describe the data. The compiler error includes parameter names in some contexts. Good names help you identify which argument is missing or extra. Name parameters clearly. Avoid generic names like a, b, data. Use width, height, payload.

Decision: Structuring arguments

E0061 often signals a design issue. If you frequently hit this error, your function signatures might be too complex. Use these patterns to reduce arity and prevent errors.

Use a struct when arguments represent a single concept. A user has a name and an email. Pass a User struct instead of two separate arguments. This groups related data and reduces the argument count.

Use a builder when arguments are optional or the count exceeds four. Builders let you set fields incrementally and call .build(). This avoids long argument lists and makes optional parameters explicit.

Use a tuple when arguments are a pair of the same type or a mathematical coordinate. Point(x, y) is clearer than new_point(x, y) if you group them. Tuples reduce the argument count to one.

Use separate functions when arguments imply different behaviors. If you have process(data, mode), and mode changes the logic drastically, split into process_read(data) and process_write(data). This eliminates the mode argument and makes the intent clear.

Use Option<T> for optional arguments. Rust has no default arguments. If a parameter is optional, make it Option<T> and handle the None case inside. This keeps the arity fixed and explicit.

Use Result for error handling instead of adding an error output parameter. Functions should return values or errors, not both via arguments. This reduces arity and follows Rust conventions.

Trust the compiler. E0061 is a feature. It forces you to write correct calls. It prevents runtime crashes. It guides you toward better API design. When you see E0061, fix the call. Then ask if the signature can be simpler. Refactor with tools. Group arguments into structs. Keep functions focused. The error is your ally.

Where to go next