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.

Level
Intro
Duration
20 min
Updated

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.

Step map

  • TASK · red textlooks like noise at first
  • TOOL · fixed structureerror[E####], -->, ^^^
  • OUTCOME · you know where to lookline, column, reason
01 / 04ERROR[CODE] · LOCATION · CAUSE

Read a type error

lib.rsDoes not compile
fn add_one(number: i32) -> i32 {
    number + 1
}

fn main() {
    let result = add_one("3"); // ERROR: expected `i32`, found `&str`
    println!("{result}");
}
The compiler says (E0308)

mismatched types. add_one expects an i32 and received a &str.

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

lib.rsDoes not compile
fn main() {
    let energy = 4;
    println!("{energie}"); // ERROR: cannot find value `energie`
}
The compiler says (E0425)

cannot find value `energie` in this scope. A similarly named variable exists: energy.

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

lib.rsCompiles
fn main() {
    let energy = 4;
    println!("still compiles");
}
The compiler says (unused_variables)

warning, not error: the program still compiles and runs.

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 default

cargo 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

Ask for the long explanation of a codemacOS · Linux · PowerShell
rustc --explain E0308

Any 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 optional note:/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.

Sources