1.7Compiler errors and how to read them
You're a handful of lessons into writing real statements, which means you're now generating compiler errors at a healthy clip. Good. This lesson is about reading them, and it isn't a digression: in Rust, the error messages are half the documentation. The difference between a frustrating week and a productive one is mostly whether you read errors or just react to them.
The anatomy of an error
Here's a program with a one-letter typo, the kind your fingers will produce daily:
fn main() {
let score = 100;
println!("final score: {}", scoer);
}error[E0425]: cannot find value `scoer` in this scope
--> src/main.rs:3:33
|
3 | println!("final score: {}", scoer);
| ^^^^^
|
help: a local variable with a similar name exists
|
3 - println!("final score: {}", scoer);
3 + println!("final score: {}", score);
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0425`.
Every Rust error has the same skeleton, so learn it once:
- The headline.
error[E0425]: cannot find valuescoerin this scope. One sentence stating the problem.E0425is an error code, a stable ID for this kind of mistake. - The location.
--> src/main.rs:3:33: file, line, column. - The span. The little excerpt of your own code with
^^^^^carets underneath, pointing at the exact characters in question. Longer errors have several spans with labels, each marking a place that contributes to the problem. - The help.
help:lines propose a concrete fix; here the compiler noticed thatscoerlooks one keyboard fumble away fromscore, and writes the suggestion as a tiny before-and-after diff: the-line is yours, the+line is the proposed replacement.note:lines, when present, explain the rule being applied.
Read in that order: what, where, suggestion. For typo-grade errors, the help line is the fix, and your job is just to believe it.
Mismatched types, a preview of your future
The error you'll see most often in Rust isn't the typo; it's E0308, mismatched types. Here's an honest specimen:
fn main() {
let x: i32 = "hello";
println!("{x}");
}error[E0308]: mismatched types
--> src/main.rs:2:18
|
2 | let x: i32 = "hello";
| --- ^^^^^^^ expected `i32`, found `&str`
| |
| expected due to this
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
This one shows off the multi-span format: one label under the value ("expected i32, found &str") and another under the type annotation explaining why an i32 was expected there. The compiler isn't just rejecting the program; it's showing its reasoning. &str is the type of string literals, which you'll meet formally in chapter 5; you can already read the gist, which is the point.
That last line of both transcripts is a real offer, by the way. Run rustc --explain E0308 in your terminal and you get a short article about that error class: what causes it, with example code, and how it's usually fixed. It's the rare error message with further reading attached.
Read the first error first
One mistake can produce a cascade. If your typo confuses the compiler about what a line means, every later line that depends on it may also "fail," and a single missing brace can produce a screenful. The discipline, the same one lesson 0.9 prescribed: scroll to the first error, fix only it, recompile. It's common for five errors to become zero.
Warnings ride along with errors in the same format, and you already know the policy from lesson 0.11: handle them as they appear, and use the _unused underscore convention when something is unused on purpose.
Key insight
Here's the course's thesis, one lesson early enough to matter. In C++, the scariest failures compile cleanly and misbehave at runtime, sometimes only on Tuesdays: reads of freed memory, off-the-end array writes, garbage values. Safe Rust moves nearly all of that to compile time. The same underlying mistakes still happen (you're human), but they arrive as error messages with file, line, carets, and a suggested fix, instead of as 2 a.m. mysteries. The strict compiler that's slowing you down this week is the thing that makes the failures legible. Learning to read its output isn't coping; it's the skill.
Tip
Your editor shows these same errors inline as red squiggles (that's rust-analyzer from lesson 0.7, running the checks as you type). Hover for the message. But when an error is longer than a hover box, the terminal's cargo build output, with its full spans and notes, is easier to read. Don't debug big errors through a tooltip keyhole.
Quiz time
Question #1
In a Rust error message, what's the difference between a help: line and a note: line?
Show solution
help: proposes a concrete fix, often with the exact code to write. note: explains the rule or reasoning behind the error. Fix from the help, learn from the note.
Question #2
You compile and get fourteen errors. What's the move?
Show solution
Read and fix the first one only, then recompile. Later errors are often echoes of the first mistake and vanish once it's fixed.
Question #3
Without compiling, predict the headline of the error this produces, as specifically as you can:
fn main() {
let widht = 800;
println!("width is {}", width);
}Show solution
Error E0425: cannot find value width in this scope, with a help line suggesting the similarly-named widht. (The compiler points at the use of the name it can't find. The actual typo is in the let line, a "where it noticed vs. where it is" case from lesson 1.1. The deeper fix is renaming the variable, not the use.)
Question #4
What does rustc --explain E0308 do, and when would you reach for it?
Show solution
It prints an extended explanation of that error class (mismatched types), with examples and typical fixes. Reach for it when the short message isn't landing and you want the article-length version.
Next up: what you're allowed to name things, and the short list of words Rust keeps for itself.