Skip to content

Rust Error E0428: The Name Is Defined Multiple Times

E0428 means you defined two things with the same name in the same place: two functions called area, two structs called User, or an enum and a struct both called Status. It often happens when you try to overload a function, the way you would in Java, C# or C++. Rust doesn’t have overloading, but it has good replacements, and this page shows them. It’s part of the compiler errors guide.

error[E0428]: the name `area` is defined multiple times
--> src/main.rs:5:1
|
1 | fn area(width: f64, height: f64) -> f64 {
| --------------------------------------- previous definition of the value `area` here
...
5 | fn area(radius: f64) -> f64 { // ❌ a second `area`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `area` redefined here
|
= note: `area` must be defined only once in the value namespace of this module

This is the program that produces it:

fn area(width: f64, height: f64) -> f64 {
width * height
}
fn area(radius: f64) -> f64 { // ❌ a second `area`
3.14159 * radius * radius
}
fn main() {
println!("{}", area(2.0, 3.0));
println!("{}", area(1.0));
}

rustc also prints a second error for this program: E0061, “this function takes 2 arguments but 1 argument was supplied”, on area(1.0). That’s only a side effect. Rust kept the first area and ignored the second, so the one-argument call no longer fits. Fix E0428 and E0061 goes away with it.

rustc points at two places:

  1. The --- line (line 1): “previous definition of the value area here”. This is the first area, the one Rust keeps.
  2. The ^^^ line (line 5): “area redefined here”. This is the second one, and it’s the one that’s rejected.
  3. The note: says area must be defined only once “in the value namespace of this module”. Each module is like one drawer, and inside a drawer every name must be unique.

For two structs, the note says “type namespace” instead. Rust keeps types (structs, enums, traits, modules) and values (functions, constants, statics) in two separate lists. That’s why a mod shapes and a fn shapes can live side by side, but two fn area or two struct User can’t.

Think of two files called report.txt in one folder. Your computer refuses the second one, not because something is wrong with it, but because report.txt would no longer tell it which file you mean.

In Rust, a name in a module points at exactly one item. When you write area(...), Rust finds the function by its name alone, not by the number or types of the arguments. That keeps things simple to read: there’s only one area to look up, and adding a new function can never quietly change which one an old call uses.

Languages with overloading pick the version from the arguments, and the rules get tricky once numbers convert into each other or default values join in. Rust chose not to do that. When you want “the same name for different inputs”, you use traits or generics, where the choice is visible in the types. More on functions in Functions.

Choose this most of the time. Two functions that take different inputs usually do different jobs, and the name can say which. If one of them was an old copy you forgot to delete, delete it instead:

fn rectangle_area(width: f64, height: f64) -> f64 {
width * height
}
fn circle_area(radius: f64) -> f64 {
3.14159 * radius * radius
}
fn main() {
println!("{}", rectangle_area(2.0, 3.0));
println!("{}", circle_area(1.0));
}

Output:

6
3.14159
▶ Try it Yourself

The standard library does the same: String::new(), String::with_capacity(10) and String::from("hi") are three different names for three ways to make a String.

Choose this when the short name really is the best name in each context, like area for each shape, or a User in your database code and a different User in your API code. Each module has its own names, so the clash disappears. Callers write the module name in front:

mod rectangle {
pub fn area(width: f64, height: f64) -> f64 {
width * height
}
}
mod circle {
pub fn area(radius: f64) -> f64 {
3.14159 * radius * radius
}
}
fn main() {
println!("{}", rectangle::area(2.0, 3.0));
println!("{}", circle::area(1.0));
}

Output:

6
3.14159
▶ Try it Yourself

Don’t forget pub, or the call from main gives E0603, “function is private”. See Modules.

Choose this when you want one call that works for many types, which is what overloading is usually for. Make a type for each kind of input, and give them a shared trait. Now every shape has its own area, and Rust picks the right one from the value’s type:

trait Shape {
fn area(&self) -> f64;
}
struct Rectangle {
width: f64,
height: f64,
}
struct Circle {
radius: f64,
}
impl Shape for Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
impl Shape for Circle {
fn area(&self) -> f64 {
3.14159 * self.radius * self.radius
}
}
fn print_area<T: Shape>(shape: &T) {
println!("Area: {}", shape.area());
}
fn main() {
print_area(&Rectangle { width: 2.0, height: 3.0 });
print_area(&Circle { radius: 1.0 });
}

Output:

Area: 6
Area: 3.14159
▶ Try it Yourself

This is more code than Fix 1, so it pays off when you have several shapes or several functions (area, perimeter, draw) that all follow the same pattern. The generic print_area<T: Shape> works for any shape you add later. See Traits and Generics.

For “the same function with or without an extra argument”, there’s a lighter option: take an Option, like fn greet(name: &str, title: Option<&str>), and call it with None or Some("Dr.").

Fix 4: Rename an import with use ... as ...

Section titled “Fix 4: Rename an import with use ... as ...”

Choose this when the clash is between your own item and a use line. Strictly speaking that’s a sibling error, E0255, with the same headline:

error[E0255]: the name `Error` is defined multiple times
--> src/main.rs:3:1
|
1 | use std::io::Error;
| -------------- previous import of the type `Error` here
2 |
3 | enum Error {
| ^^^^^^^^^^ `Error` redefined here
|
= note: `Error` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
|
1 | use std::io::Error as OtherError;
| +++++++++++++

Give the import a local nickname with as. Pick a name that says where it comes from, like IoError, rather than rustc’s placeholder OtherError:

use std::io::Error as IoError;
use std::io::ErrorKind;
#[derive(Debug)]
enum Error {
NotFound(String),
Invalid(u32),
}
fn main() {
let mine = Error::NotFound(String::from("config.toml"));
let other = Error::Invalid(42);
let disk = IoError::new(ErrorKind::Other, "disk is full");
println!("{:?}", mine);
println!("{:?}", other);
println!("{}", disk);
}

Output:

NotFound("config.toml")
Invalid(42)
disk is full
▶ Try it Yourself

Two use lines that clash, like use std::fmt::Result; and use std::io::Result;, give a third sibling, E0252 (`Result` reimported here). The fix is the same: use std::io::Result as IoResult;, or import the module (use std::io;) and write io::Result. Renaming your own enum (AppError) works too.

Overloading a method in an impl block. Two fn new in impl Timer give a different code, E0592: duplicate definitions with name `new` . Same cause, same fix: name them for what they do, like Timer::new() and Timer::with_seconds(30). See Structs.

Copy-paste while refactoring. You copy a function to change it, or paste a struct User from another file, and forget to remove the old one. Also common in tests: two #[test] fn it_works() in one mod tests give E0428. Fix: delete the old copy, or rename the test.

Duplicate enum variants. enum Color { Red, Red } gives E0428 too, pointing at the second Red, with the note “type namespace of this enum”. Fix: remove or rename the duplicate variant. See Enums.

  • E0061: wrong number of arguments. Often printed right after E0428 when you tried to overload a function.
  • E0425: the opposite problem: a name that’s defined zero times where you use it.
  • E0433: a path like circle::area whose first part (the module) can’t be found.
  • E0034: two traits give a type methods with the same name; you need to say which one you mean.
  • E0255 (a use clashes with a local item), E0252 (two use lines clash), E0592 (duplicate method in an impl): the siblings shown above.
  • All compiler errors: the full list of error pages.

Quick check

1. You write fn total(a: u32) and fn total(a: u32, b: u32) in one file. What happens?

2. Can mod report and fn report() live in the same module?

3. Your file has use std::fmt::Result; and you define enum Result. What's a clean fix?

Score: 0 / 3