Skip to content

Rust Error E0412: Cannot Find Type in This Scope

E0412 means you wrote a type name that Rust can’t see from that spot, for example in a function signature like fn print_invoice(inv: &Invoce). It’s a very common error and an easy one: a typo, a missing use line, or a generic <T> you forgot to declare. One thing may confuse you first: since Rust 1.93, the compiler prints this error as E0425, with the same message, cannot find type. This page covers both, and it’s part of the compiler errors guide.

This is what Rust 1.93 and newer print (the current compiler is 1.97):

error[E0425]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce
| ^^^^^^
|
help: a struct with a similar name exists
|
2 | fn print_invoice(inv: &Invoice) { // ❌ typo: Invoce
| +

And this is the same program on Rust 1.92 or older, the version most blog posts and Stack Overflow answers were written with:

error[E0412]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) {
| ^^^^^^ help: a struct with a similar name exists: `Invoice`

This is the program that produces both:

struct Invoice { total: u32 }
fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce
println!("{}", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

The official E0412 page now starts with “this error code is no longer emitted by the compiler”. The problem didn’t go away, it just moved to E0425, which also covers missing variables and functions. Everything below works the same for both codes.

The ^^^^^^ points at Invoce in the signature. To check this function, Rust has to know what an Invoce is: how big it is, which fields it has. It looked at every type visible from line 2 (your own structs and enums, your use lines and the prelude) and found nothing with that name.

The help: line tells you which situation you’re in:

  • “a struct with a similar name exists”: a typo. The + shows the missing letter.
  • “consider importing this struct”: the type exists somewhere else, and you need a use line.
  • “you might be missing a type parameter”: you used a generic T without declaring <T>.
  • no help at all: the type doesn’t exist yet. You haven’t written it, or it’s in a file Rust doesn’t know about.

It’s like a recipe that says “add 200 g of Invoce”. The cook knows what flour and sugar are, but not “Invoce”, so they stop before they even start.

Rust checks every function’s signature before the program runs. Each parameter and return type must name a real, known type, because Rust uses it to decide how much memory the value needs and which methods and fields it has. A name it can’t find is not a guess it’s willing to make.

Only a small set of type names is visible everywhere without a use: the prelude, with String, Vec, Option, Result, Box and a few more. Everything else needs either your own definition, a use line, or a full path like std::num::ParseIntError. See Modules for how paths and use work.

Why did the code change? Since Rust 1.93, rustc reports a missing type under E0425, the same code it already used for a missing variable or function. The message still says type, so you can always tell which kind of name went missing.

Fix 1: Fix the spelling, or define the type

Section titled “Fix 1: Fix the spelling, or define the type”

Choose this when rustc says a similar name exists, or gives no help at all. Type names are case-sensitive: invoice, Invoce and Invoice are three different names. If there’s no similar name, write the struct or enum first:

struct Invoice {
total: u32,
}
fn print_invoice(inv: &Invoice) {
println!("Invoice total: {} EUR", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

Output:

Invoice total: 120 EUR
▶ Try it Yourself

Choose this when the help says consider importing this struct (or enum, or type alias). Types from the standard library outside the prelude, like HashMap, ParseIntError or Ordering, need a use line. Here a function returns a parse error:

error[E0425]: cannot find type `ParseIntError` in this scope
--> src/main.rs:1:40
|
1 | fn parse_age(text: &str) -> Result<u8, ParseIntError> {
| ^^^^^^^^^^^^^ not found in this scope
|
help: consider importing this struct
|
1 + use std::num::ParseIntError;
|

Copy the suggested line to the top of the file:

use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> {
text.trim().parse()
}
fn main() {
println!("{:?}", parse_age(" 42 "));
println!("{:?}", parse_age("forty").is_err());
}

Output:

Ok(42)
true
▶ Try it Yourself

If you wrote HashMap::new() (a path with ::) rather than a type in a signature, the error is E0433 instead, and the same use line fixes it. If rustc suggests several imports, read them before choosing; they are different types that share a name.

Choose this when the help says you might be missing a type parameter. In Rust, T is not a special word. It’s a name you invent, and you have to announce it in angle brackets after the function name. Without <T>, Rust looks for a real type called T:

error[E0425]: cannot find type `T` in this scope
--> src/main.rs:1:21
|
1 | fn largest(items: &[T]) -> &T {
| ^ not found in this scope
|
help: you might be missing a type parameter
|
1 | fn largest<T>(items: &[T]) -> &T {
| +++

You get the same error once for every place T appears. Add <T>, plus any trait the function needs. To compare items with >, T must implement PartialOrd:

fn largest<T: PartialOrd>(items: &[T]) -> &T {
let mut best = &items[0];
for item in items {
if item > best {
best = item;
}
}
best
}
fn main() {
println!("{}", largest(&[34, 50, 25, 100, 65]));
println!("{}", largest(&['y', 'm', 'a', 'q']));
}

Output:

100
y
▶ Try it Yourself

The same goes for structs: struct Wrapper { items: Vec<Item> } fails unless you write struct Wrapper<Item> or define a real Item type. Leave out : PartialOrd and you get E0369 on the > instead. See Generics.

Choose this when the type is yours but lives in a different module. A common surprise: a module inside your file can’t see the types at the top of the file either. Each module has its own scope:

error[E0425]: cannot find type `Order` in this scope
--> src/main.rs:7:26
|
7 | pub fn print(order: &Order) -> String {
| ^^^^^ not found in this scope
|
help: consider importing this struct
|
7 + use crate::Order;
|

The 7 + means “add this line inside the module, at line 7”. crate::Order is the path from the top of your crate; super::Order (“from the parent module”) works too:

struct Order {
id: u32,
total: u32,
}
mod receipts {
use crate::Order;
pub fn print(order: &Order) -> String {
format!("Order #{}: {} EUR", order.id, order.total)
}
}
fn main() {
let order = Order { id: 7, total: 42 };
println!("{}", receipts::print(&order));
}

Output:

Order #7: 42 EUR
▶ Try it Yourself

The other direction works the same way: a type defined in mod shop needs pub struct Product and use crate::shop::Product; (or the full path shop::Product) before main can name it. You’ll meet this most in mod tests, where use super::*; at the top imports everything from the parent.

A type from a file you haven’t declared. fn save(user: models::User) with a src/models.rs file but no mod models; line is not E0412 or E0425 but E0433: cannot find module or crate `models` in this scope. Fix: add mod models; at the top of main.rs, and make the struct pub.

Self outside an impl. fn new_counter() -> Self at the top level gives its own code, E0411: cannot find type `Self` in this scope, with the label `Self` is only available in impls, traits, and type definitions. Fix: move the function into impl Counter { ... }, or write Counter instead of Self.

A trait instead of a type. impl Display for Point without importing Display gives E0405, cannot find trait `Display` in this scope, with help: consider importing this trait, use std::fmt::Display;. Same idea, same fix: add the use line. See Traits.

  • E0425: cannot find value, function, and since Rust 1.93 also type. The code you’ll actually see today.
  • E0433: cannot find the first part of a path like HashMap::new() or models::User.
  • E0432: unresolved import, when the use line itself points at nothing.
  • E0603: the type was found, but it isn’t pub.
  • E0405 (cannot find trait) and E0411 (Self outside an impl): the close cousins shown above.
  • All compiler errors: the full list of error pages.

Quick check

1. You followed a tutorial that shows error[E0412]: cannot find type, but your compiler prints error[E0425]: cannot find type. Why?

2. fn first(items: &[T]) -> &T gives cannot find type T. What's the fix?

3. A function inside mod billing uses Order, a struct defined at the top of main.rs. Which line, inside the module, fixes it?

Score: 0 / 3