A million thanks to everyone who’s worked on those error messages. More than any other language I’ve ever used, Rust goes to great lengths to explain exactly you did wrong, with enough context to demonstrate it, and an explanation of why it’s wrong, pointers of where to learn more about it, and how to fix it.
Yes, Rust has some inherently tricky parts that require programmers to really understand them before they can write it effectively. However, it goes out of its way to teach those concepts more than I realized it was possible for a compiler to do.
When I was first developing early versions of rustc I was really fascinated with Clang's effort at good error messages, which was helping it gain traction vs. GCC at the time, and I tried to start the Rust compiler project off on the right foot. I'm really glad that the Rust compiler dev community has continued to value great error messages: they're the UX of a compiler, and are every bit as important as UX of any other app.
I don't remember where, but I once heard someone talk about "error-message-driven-development" in Rust -- that is, using the error messages provided by rustc to guide you in your development process by way of fixing bugs in naively-written code. I even did a talk to several dozen engineers in my previous group about how fantastic it is: a newbie can write what they think is reasonable code, the compiler will reject the program but provide useful information, and the user can iteratively apply changes to the point where you can almost get things exactly as you want it. A lot of people who knew nothing about Rust were super impressed by the messages reported.
Many thanks to you and others that have toiled at this incredible UX!
When an error happens it's the best time to teach the user something. If you can figure it what they were trying to do something, you can tell them why what they tried to do doesn't work, and what to try instead.
With LLM's And Reason-Act agents on the table, this is more higher stakes than ever, AI has no issues on reading stack traces or verbose error logs where a human might have overlooked before, and it creates a really nice loop if the AI can reason with new context provider by the error messages
Effective error messages are one of my platonic ideals about how documentation is supposed to work. The docs shouldn't be shoved off to the side. They should appear just-in-time, when you need them. If you can fix the error within the product (e.g. when Rust tells you exactly how to fix the typo), just do it there. Otherwise link off to the full docs when it's too much content.
The general platonic ideal is "have the product automatically fix the issue" => "provide short documentation within the product if the problem can be explained with just a paragraph or two of content" => "link to a targeted doc that deals with this exact problem if it takes more than a few paragraphs to explain"
A lot of time, my work as a technical writer is advocating to update the product (or updating the product myself) to do the first two steps, rather than just jumping immediately to the last step. Startup people often refer to this as "the perfect product requires 0 documentation." When teams always resort to fixing product issues with docs, your docs start to get huge and complicated. We technical writers often refer to this as "putting docs lipstick on the product pig."
Yes, the article goes to some length to mention this but it's worth re-stating, this is all real work, people spent a bunch of effort improving Rust's diagnostics, it's not the case that somehow the errors magically get better as the compiler's optimisations improve or something, if you did X and that can't work but the compiler said how about Y, that probably means a person like you had a similar situation and they put work into modifying the diagnostics when you can't do X so that it realises it should suggest Y.
My tiny contribution is that when you write say '$' (the dollar symbol as a Unicode char) in a context where you needed a single byte, now rustc will suggest prefixing with a b to make b'$' (the ASCII code of a dollar as a single byte) rather than just telling you that's the wrong type, and yet if you write '€' (the Euro symbol as a Unicode char) it will not suggest b'€' because that's not a thing, the Euro isn't a single byte in ASCII
[Yes in some modern 8-bit encodings € exists but those encodings aren't used in Rust, which favours UTF-8, so b'€' wouldn't make sense, in UTF-8 this symbol is 3 bytes]
> The general platonic ideal is "have the product automatically fix the issue"
`cargo fix` will apply programmatic suggestions from rustc. We are very conservative of which suggestions we apply but will expand it when we add an interactive mode.
This is an approach that I really like because of some not necessarily obvious properties: the behavior of the code as written is easily predictable, while still getting the benefits of a compiler's help. The suggestions can be more aggressive than automatic changes, because a human is in the loop and they can apply judgement of whether a certain strategy is beneficial or not.
We can also offer more precise choices: say you have an ambiguous `Deref`, instead of saying `T` in the turbofish (for brevity), we could let the user select from the different available `Deref` impls what should be inserted.
This reminds me of http://brson.github.io/archaea/, which is a really fantastic project by Brian Anderson. It shows iterations of Rust's test files over the years, so you can see what older Rust syntax looked like.
Interesting enough i still hear people say the error messages from rust is confusing and none informative. I wouldn't say that i am proficient in Rust but i know enough about it and it;s tooling to distinguish the difference between different (LV " Low Level " ) languages. When you get a grasp of the Rust lang then you will know how helpful the compiler is in Rust compared to other languages. Highlighting the progress of the Rust lang compiler messages in this post really Depicts the refinement of their ( Rust lang team ) compiler messages.
When maintaining a project, one gets exposed to the worst parts of it at an elevated rate. This makes maintainers be more critical than most, as we have an skewed view of the projects faults. So I can absolutely understand when someone claims that rustc has bad errors. I've seen them. But for most people most of the time the output is actually quite good. That shouldn't stop us from being better. I'm thankful for the OP because it does show that we do improve over time.
I keep saying that the most effective thing we can do to help someone learning the language is to tell them to try in 6 months (as we expect it'll be better then).
The wrong field error message change in 1.87 really is brilliant. Instead of just pointing out the correct field, it actually points out the spelling change needed to get to that field.
This visualization is breathtaking, thanks for making it.
Sometimes I want an excuse to write some Rust. I think I'll make one in my upcoming web app, since it already uses web workers. I guess the side effect is that wasm (and therefore Rust) will become a first class citizen in my app? Neat.
I really wish there would be rust version with optional borrow checker :)
I want to have a modern "C" with such good error messages. Idk why gcc spits out incomprehensible garbage if you forgot a semicolon
I'm surprised 1.0 didn't have the error codes. Error codes should be table stakes for anything that produces errors, really (Looking at you, proprietary codebases where I was putting in error codes while other people were writing the C++ equivalent of `.expect("the value to be right")`)
I was a big advocate of adding error codes. I don't remember specifically the timeline, but we had so much stuff to do for 1.0, it doesn't surprise me that it got pushed back a bit.
At the time, I was thinking about the big old chunky Visual Basic manuals I used to own, and how useful those were.
> This implements the minimal scaffolding that allows mapping diagnostic messages to alpha-numeric codes, which could improve the searchability of errors. In addition, there's a new compiler option, `--explain {code}` which takes an error code and prints out a somewhat detailed explanation of the error.
committed on Jul 10, 2014
I think I've figured out what happened here: the particular error that was chosen didn't have a code until 1.2. The example from this commit does show a code on Rust 1.0.0: https://godbolt.org/z/14hcb3ETG
My recollection is that Brian Anderson, who came from the C# world, was an early advocate of the easily-googlable error codes that Microsoft compilers use a lot, and pushed to get them in. That was a good call. (In general Brian had a lot of behind-the-scenes positive influence on Rust: my favorite brson-ism is "if the code doesn't have a test it doesn't exist".)
Yeah this PR cites it as explicitly a continuation of Bryan’s work. I never did any implementation work on errors, I was just a big fan of the codes concept.
A million thanks to everyone who’s worked on those error messages. More than any other language I’ve ever used, Rust goes to great lengths to explain exactly you did wrong, with enough context to demonstrate it, and an explanation of why it’s wrong, pointers of where to learn more about it, and how to fix it.
Yes, Rust has some inherently tricky parts that require programmers to really understand them before they can write it effectively. However, it goes out of its way to teach those concepts more than I realized it was possible for a compiler to do.
When I was first developing early versions of rustc I was really fascinated with Clang's effort at good error messages, which was helping it gain traction vs. GCC at the time, and I tried to start the Rust compiler project off on the right foot. I'm really glad that the Rust compiler dev community has continued to value great error messages: they're the UX of a compiler, and are every bit as important as UX of any other app.
I don't remember where, but I once heard someone talk about "error-message-driven-development" in Rust -- that is, using the error messages provided by rustc to guide you in your development process by way of fixing bugs in naively-written code. I even did a talk to several dozen engineers in my previous group about how fantastic it is: a newbie can write what they think is reasonable code, the compiler will reject the program but provide useful information, and the user can iteratively apply changes to the point where you can almost get things exactly as you want it. A lot of people who knew nothing about Rust were super impressed by the messages reported.
Many thanks to you and others that have toiled at this incredible UX!
When an error happens it's the best time to teach the user something. If you can figure it what they were trying to do something, you can tell them why what they tried to do doesn't work, and what to try instead.
With LLM's And Reason-Act agents on the table, this is more higher stakes than ever, AI has no issues on reading stack traces or verbose error logs where a human might have overlooked before, and it creates a really nice loop if the AI can reason with new context provider by the error messages
Effective error messages are one of my platonic ideals about how documentation is supposed to work. The docs shouldn't be shoved off to the side. They should appear just-in-time, when you need them. If you can fix the error within the product (e.g. when Rust tells you exactly how to fix the typo), just do it there. Otherwise link off to the full docs when it's too much content.
The general platonic ideal is "have the product automatically fix the issue" => "provide short documentation within the product if the problem can be explained with just a paragraph or two of content" => "link to a targeted doc that deals with this exact problem if it takes more than a few paragraphs to explain"
A lot of time, my work as a technical writer is advocating to update the product (or updating the product myself) to do the first two steps, rather than just jumping immediately to the last step. Startup people often refer to this as "the perfect product requires 0 documentation." When teams always resort to fixing product issues with docs, your docs start to get huge and complicated. We technical writers often refer to this as "putting docs lipstick on the product pig."
Yes, the article goes to some length to mention this but it's worth re-stating, this is all real work, people spent a bunch of effort improving Rust's diagnostics, it's not the case that somehow the errors magically get better as the compiler's optimisations improve or something, if you did X and that can't work but the compiler said how about Y, that probably means a person like you had a similar situation and they put work into modifying the diagnostics when you can't do X so that it realises it should suggest Y.
My tiny contribution is that when you write say '$' (the dollar symbol as a Unicode char) in a context where you needed a single byte, now rustc will suggest prefixing with a b to make b'$' (the ASCII code of a dollar as a single byte) rather than just telling you that's the wrong type, and yet if you write '€' (the Euro symbol as a Unicode char) it will not suggest b'€' because that's not a thing, the Euro isn't a single byte in ASCII
[Yes in some modern 8-bit encodings € exists but those encodings aren't used in Rust, which favours UTF-8, so b'€' wouldn't make sense, in UTF-8 this symbol is 3 bytes]
> The general platonic ideal is "have the product automatically fix the issue"
`cargo fix` will apply programmatic suggestions from rustc. We are very conservative of which suggestions we apply but will expand it when we add an interactive mode.
This is an approach that I really like because of some not necessarily obvious properties: the behavior of the code as written is easily predictable, while still getting the benefits of a compiler's help. The suggestions can be more aggressive than automatic changes, because a human is in the loop and they can apply judgement of whether a certain strategy is beneficial or not.
We can also offer more precise choices: say you have an ambiguous `Deref`, instead of saying `T` in the turbofish (for brevity), we could let the user select from the different available `Deref` impls what should be inserted.
This reminds me of http://brson.github.io/archaea/, which is a really fantastic project by Brian Anderson. It shows iterations of Rust's test files over the years, so you can see what older Rust syntax looked like.
Regardless, very cool!
Wow, you're right. Apparently this was Rust in 2010-06-23:
Yep! Some interesting things in here:
`io fn`, there were three effects: io, state, and unsafe. There was also pure, for functions with no effect.
chan for channels. <| was a "semi-synchronous message send," it blocked if the queue was full.
square brackets for generics
int was two's compliment signed integer with machine dependent size
log for printing to the screen
Interesting enough i still hear people say the error messages from rust is confusing and none informative. I wouldn't say that i am proficient in Rust but i know enough about it and it;s tooling to distinguish the difference between different (LV " Low Level " ) languages. When you get a grasp of the Rust lang then you will know how helpful the compiler is in Rust compared to other languages. Highlighting the progress of the Rust lang compiler messages in this post really Depicts the refinement of their ( Rust lang team ) compiler messages.
When maintaining a project, one gets exposed to the worst parts of it at an elevated rate. This makes maintainers be more critical than most, as we have an skewed view of the projects faults. So I can absolutely understand when someone claims that rustc has bad errors. I've seen them. But for most people most of the time the output is actually quite good. That shouldn't stop us from being better. I'm thankful for the OP because it does show that we do improve over time.
I keep saying that the most effective thing we can do to help someone learning the language is to tell them to try in 6 months (as we expect it'll be better then).
The wrong field error message change in 1.87 really is brilliant. Instead of just pointing out the correct field, it actually points out the spelling change needed to get to that field.
That was done by @compiler-errors, as part of an improvement to make some of the suggestions I introduced easier to read.
The helpful error messages are one of the reasons I love rust. Perhaps even the top reason.
This is something that I never get tired to hear. I'm really glad that you've found them helpful.
This was a fantastic read — thanks for putting in the work to script and visualize the evolution of Rust's compiler errors
This is surprisingly cool. Now I want to see it for GCC (and mark the point where Clang was released!).
this was cool, this should be a standard way to show various kinds of diffs
This visualization is breathtaking, thanks for making it.
Sometimes I want an excuse to write some Rust. I think I'll make one in my upcoming web app, since it already uses web workers. I guess the side effect is that wasm (and therefore Rust) will become a first class citizen in my app? Neat.
I really wish there would be rust version with optional borrow checker :) I want to have a modern "C" with such good error messages. Idk why gcc spits out incomprehensible garbage if you forgot a semicolon
I'm surprised 1.0 didn't have the error codes. Error codes should be table stakes for anything that produces errors, really (Looking at you, proprietary codebases where I was putting in error codes while other people were writing the C++ equivalent of `.expect("the value to be right")`)
I was a big advocate of adding error codes. I don't remember specifically the timeline, but we had so much stuff to do for 1.0, it doesn't surprise me that it got pushed back a bit.
At the time, I was thinking about the big old chunky Visual Basic manuals I used to own, and how useful those were.
EDIT: okay, so I'm doing some digging: error codes were added before 1.0... https://github.com/rust-lang/rust/commit/0e80dbe59ea986ea53c...
> This implements the minimal scaffolding that allows mapping diagnostic messages to alpha-numeric codes, which could improve the searchability of errors. In addition, there's a new compiler option, `--explain {code}` which takes an error code and prints out a somewhat detailed explanation of the error.
committed on Jul 10, 2014
I think I've figured out what happened here: the particular error that was chosen didn't have a code until 1.2. The example from this commit does show a code on Rust 1.0.0: https://godbolt.org/z/14hcb3ETG
My recollection is that Brian Anderson, who came from the C# world, was an early advocate of the easily-googlable error codes that Microsoft compilers use a lot, and pushed to get them in. That was a good call. (In general Brian had a lot of behind-the-scenes positive influence on Rust: my favorite brson-ism is "if the code doesn't have a test it doesn't exist".)
Yeah this PR cites it as explicitly a continuation of Bryan’s work. I never did any implementation work on errors, I was just a big fan of the codes concept.