Skip to content

Rust Error E0411: Cannot Find Type Self in This Scope

E0411 means you wrote Self somewhere Rust can’t tell what it stands for. Self is a shortcut for “the type this impl block (or trait) is about”, so it only works inside an impl, a trait, or a type definition. The usual cause is a constructor like fn new() -> Self written at the top level of a file, or a method you copied out of its impl block. It’s common and quick to fix. Unlike E0412, which became E0425 in Rust 1.93, this code hasn’t changed: rustc 1.97 still prints E0411. It’s part of the compiler errors guide.

error[E0411]: cannot find type `Self` in this scope
--> src/main.rs:5:21
|
5 | fn new_counter() -> Self { // ❌ `Self` outside an `impl`
| ----------- ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function

This is the program that produces it:

struct Counter {
count: u32,
}
fn new_counter() -> Self { // ❌ `Self` outside an `impl`
Counter { count: 0 }
}
fn main() {
let c = new_counter();
println!("{}", c.count);
}

rustc points at two things on line 5:

  1. The ^^^^ under Self: “Self is only available in impls, traits, and type definitions”. That’s the rule, in one line.
  2. The ----- under new_counter: “Self not allowed in a function”. This is the reason here: new_counter is a plain function, not part of any impl.

You may know that new_counter returns a Counter, because you just wrote Counter { count: 0 }. But Rust doesn’t read the body to guess what Self means. Self gets its meaning only from an enclosing impl Counter { ... } or trait ... { ... }, and here there is none.

It’s like the word “here” on a sticky note. On a map, “you are here” makes sense. On a note lying on the kitchen table, nobody knows where “here” is.

Self is not a type of its own. It’s a placeholder that each impl or trait fills in: inside impl Counter, Self means Counter; inside impl Timer, it means Timer; inside a trait, it means “whichever type implements this trait”. That’s what makes it useful: you can rename the struct, or copy a method into another impl, and Self follows along.

A free function belongs to no type, so there’s nothing to fill in. Rust could try to guess from the body, but then a signature would depend on the code inside it, and Rust deliberately checks signatures on their own. See Structs for the usual home of fn new() -> Self.

Fix 1: Move the function into an impl block

Section titled “Fix 1: Move the function into an impl block”

Choose this most of the time. A function that creates or works with one type belongs in that type’s impl block, and there Self works as you expected. Call it with Counter::new():

struct Counter {
count: u32,
}
impl Counter {
fn new() -> Self {
Self { count: 0 }
}
fn increment(&mut self) {
self.count += 1;
}
}
fn main() {
let mut c = Counter::new();
c.increment();
c.increment();
println!("{}", c.count);
}

Output:

2
▶ Try it Yourself

Inside the impl, you can use Self both as a type (-> Self) and to build a value (Self { count: 0 }). See Structs.

Fix 2: Write the type’s name instead of Self

Section titled “Fix 2: Write the type’s name instead of Self”

Choose this when the function should stay a free function, for example a helper that builds several types, or one that lives in another module. Just write the real type, Counter, where you wrote Self:

struct Counter {
count: u32,
}
fn new_counter(start: u32) -> Counter {
Counter { count: start }
}
fn reset(c: &mut Counter) {
c.count = 0;
}
fn main() {
let mut c = new_counter(10);
println!("{}", c.count);
reset(&mut c);
println!("{}", c.count);
}

Output:

10
0
▶ Try it Yourself

This is also the fix for fn reset(c: &mut Self) copied out of an impl: every Self in the signature and the body becomes Counter.

Fix 3: Use a generic type if you meant “any type”

Section titled “Fix 3: Use a generic type if you meant “any type””

Choose this when you used Self to mean “whatever type the caller wants”, which is a job for a generic T, not Self. Declare <T> with the traits the function needs. Here, T: Default lets the function create a starting value of any type:

fn fresh_pair<T: Default>() -> (T, T) {
(T::default(), T::default())
}
fn main() {
let numbers: (u32, u32) = fresh_pair();
let words: (String, String) = fresh_pair();
println!("{:?}", numbers);
println!("{:?}", words);
}

Output:

(0, 0)
("", "")
▶ Try it Yourself

If you want each type to decide how it’s built, put the function in a trait: trait Reset { fn fresh() -> Self; }. Inside a trait, Self means “the type that implements it”. See Generics and Traits.

Self { ... } in main or a free function. let c = Self { count: 0 }; gives E0411 with a slightly different headline: cannot find struct, variant or union type `Self` in this scope. Fix: write Counter { count: 0 }, or call Counter::new().

A helper function nested inside a method. Inside impl Counter, a method that contains its own fn helper() -> Self gets a different code, E0401: can't use `Self` from outer item. A function inside a function doesn’t inherit the outer impl. Fix: write Counter in the inner function, or use a closure, or move helper up into the impl as its own method.

Mixing up Self and self. Capital Self is the type; lowercase self is the value a method is called on. Using self outside a method is a different error, E0424. Fix for both: make sure the code sits inside the right impl block.

  • E0424: self (lowercase, the value) used outside a method.
  • E0425: cannot find a value, function or (since Rust 1.93) type with a normal name.
  • E0412: the old code for “cannot find type”, now reported as E0425.
  • E0405: cannot find a trait, usually a missing use line.
  • E0401: Self from an outer impl used inside a nested function, shown above.
  • All compiler errors: the full list of error pages.

Quick check

1. Where can you use Self as a type?

2. fn make_user() -> Self at the top level gives E0411. What's the usual fix?

3. Inside impl Counter, what does Self { count: 0 } create?

Score: 0 / 3