Lesson 4
How to read the compiler
Decode the structure of a rustc error, diagnose a type mismatch and an unresolved name, and learn to tell warnings apart from errors.
The first red error is not a dead end
In the previous lesson you walked through the check → build → run cycle.
Sooner or later one of those commands is going to fail and your terminal
will fill up with red text. That “this is unreadable” reaction is the most
common one when starting out, but the message has a fixed structure and,
almost always, tells you exactly what to fix and where.
Read a type error
fn add_one(number: i32) -> i32 {
number + 1
}
fn main() {
let result = add_one("3"); // ERROR: expected `i32`, found `&str`
println!("{result}");
}error[E0308]: mismatched types
--> src/main.rs:6:26
|
6 | let result = add_one("3");
| ------- ^^^ expected `i32`, found `&str`
| |
| arguments to this function are incorrect
|
note: function defined here
--> src/main.rs:1:4
|
1 | fn add_one(number: i32) -> i32 {
| ^^^^^^^ -----------The message points at two spots at once: where you called the function with
the wrong type (^^^) and where that function was defined (note:). To
fix it, you either convert the value to the right type or change the
signature; here you would need to parse "3" into an i32 before calling
add_one.
When the compiler suggests the name
fn main() {
let energy = 4;
println!("{energie}"); // ERROR: cannot find value `energie`
}error[E0425]: cannot find value `energie` in this scope
--> src/main.rs:3:16
|
3 | println!("{energie}");
| ^^^^^^^
|
help: a local variable with a similar name exists
|
3 - println!("{energie}");
3 + println!("{energy}");
|Here the help: does not just say what is wrong, it proposes the exact
fix: remove energie and write energy. When rustc finds a similarly
spelled name declared nearby, it almost always suggests it like this.
A warning does not stop you
fn main() {
let energy = 4;
println!("still compiles");
}warning: unused variable: `energy`
--> src/main.rs:2:9
|
2 | let energy = 4;
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_energy`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by defaultcargo build/cargo run finish all the same: the binary gets built, runs,
and prints still compiles. The warning just stays as a heads-up in the
terminal, not as a blocker.
Dig deeper with rustc –explain
rustc --explain E0308Any code shaped like E#### accepts this command: it prints the same
extended explanation that lives in the official error index, but offline
and without leaving the terminal.
What this lesson does not cover
- It does not cover borrow checker errors (
E0502,E0499…): those arrive with the ownership module. - It does not repeat Clippy lints, already covered in the installation lesson: Clippy warns about style and idiomatic code, rustc about whether the program is valid at all.
- It does not explain how your editor shows these same diagnostics underlined live: that is rust-analyzer, also covered before.
What’s next
With the ability to read an error and know where to look, the next block of the curriculum moves into real Rust syntax: variables, types, expressions, and functions, the foundation you will build every program on from here on.
Summary
- A rustc error has a fixed structure:
error[CODE], an arrow-->with the exact location, the fragment marked with^^^, and optionalnote:/help:blocks. - E0308 (types that do not fit) points to both the call site and the definition involved; Rust has no implicit conversion between types.
- E0425 (name not found) often comes with a
help:that directly proposes the right name when a similar one exists nearby. - A warning does not stop compiling or running; an error does.
rustc --explain E####expands on any code offline.