{"slug": "thiserror", "name": "thiserror", "category": "dev-libs", "category_name": "Libraries and frameworks", "description": "", "recommenders": 6, "commenters": 15, "warners": 7, "score": -0.238, "rising": -1.96, "first": "2025-11-13", "latest": "2026-08-20", "why": "thiserror for libraries, helping you create the standard library error types", "why_is_quote": true, "has_verdict": false, "sentiment": {"recommend": 6, "neutral": 2, "compare": 0, "warn": 7}, "spark": [0, 1, 2, 1, 0, 0, 2, 0, 0, 0, 0, 0], "listed": true, "loved": [], "caveat": "", "short_quote": "thiserror for libraries, helping you create the standard library error types", "kind": "", "icon": false, "domain": null, "github_repo": null, "official_url": "https://github.com/dtolnay/thiserror", "pricing": "", "aliases": ["thiserror"], "verdict": null, "praise": [{"label": "", "summary": "", "quotes": [{"id": 772195136, "item_id": 48262196, "url": "https://news.ycombinator.com/item?id=48262196", "by": "ViewTrick1002", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "The example on the docs page is quite clear", "excerpt": "How come you get macro expansion errors? Or is it because you write incorrect syntax in the enum error definitions? The example on the docs page is quite clear: https://docs.rs/thiserror/latest/thiserror/#example Including all kinds of errors: Strings, tagged unions and automatically converting from std::io::Error with added context. That one page document is the entire documentation for the thiserror crate.", "context": "", "use_case": "Rust error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 772190320, "item_id": 48261895, "url": "https://news.ycombinator.com/item?id=48261895", "by": "LoganDark", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "I use thiserror a lot to help with my impls.", "excerpt": "thiserror and anyhow are just std::error with extra steps. Note that io::error is just a specific std::error. The entire point in Rust is that you wrap Error impls with other Error impls, or translate one impl into another using a match. I've found this is far more flexible and verifiable than most other languages, because if you craft your error types with enough rigor, you can basically have a complete semantic bac", "context": "", "use_case": "Rust error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 772179105, "item_id": 48261194, "url": "https://news.ycombinator.com/item?id=48261194", "by": "ViewTrick1002", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "thiserror for libraries, helping you create the standard library error types", "excerpt": "They all convert seamlessly, and the enums make the branches explicit. Don't even need to check the documentation to find which errors supposedly exists like in Go with its errors.Is, errors.As, wrapping and what not. An easy rule before you make a knowledge based choice is thiserror for libraries, helping you create the standard library error types and anyhow for applications, easy strings you bubble up. Or just go ", "context": "", "use_case": "library error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 750598880, "item_id": 46912430, "url": "https://news.ycombinator.com/item?id=46912430", "by": "bumahkib7", "date": "2026-02-06", "version": null, "stance": "recommend", "quote": "A single crate level errors.rs with thiserror makes big repos feel way less messy.", "excerpt": "This is super interesting. The \u201cmake everything look the same\u201d angle is exactly what AI generated monorepos need if you want reviews to stay sane. The absolute paths rule and the \u201cno cycles unless same module\u201d rule are both clean. I like that you\u2019re optimizing for navigation too, not just style. The two \u201cwould be nice\u201d points hit hard: A single crate level errors.rs with thiserror makes big repos feel way less messy.", "context": "", "use_case": "", "switched_from": "", "story": "RMA \u2013 Fast Rust monorepo scanner cross-file taint, typestate, <0.5s on 100k LOC"}, {"id": 744789824, "item_id": 46549364, "url": "https://news.ycombinator.com/item?id=46549364", "by": "bccdee", "date": "2026-01-08", "version": null, "stance": "recommend", "quote": "thiserror\u00b9 for libraries, anyhow\u00b2 for applications", "excerpt": "> There is good reason why even the languages that support defined error sets have trended back to using open-ended constructs. Rust does it that way & has never trended in any other direction. The generally-accepted wisdom is \"thiserror\u00b9 for libraries, anyhow\u00b2 for applications\"\u2014i.e., any error that's liable to be handled by a machine should be an enum of exhaustively-matchable error kinds, whereas anything that's ju", "context": "", "use_case": "Rust error handling", "switched_from": "", "story": "An Honest Review of Go"}]}], "caveats": [{"label": "", "summary": "", "quotes": [{"id": 790084290, "item_id": 49380268, "url": "https://news.ycombinator.com/item?id=49380268", "by": "echelon", "date": "2026-08-20", "version": null, "stance": "warn", "quote": "I wouldn't want to see anyhow, thiserror, anything opinionated", "excerpt": "Good ideas are pulled into the standard library. https://crates.io/crates/once_cell https://doc.rust-lang.org/std/cell/struct.OnceCell.html Not everything should be eligible for this treatment. Certainly not an HTTP library or something without extremely widespread applicability. Nearly all of my projects used once_cell, so it's good to see that pulled in. I wouldn't want to see anyhow, thiserror, anything opinionate", "context": "", "use_case": "", "switched_from": "", "story": "Malicious Rust Crate Arrayref Runs a Build-Time Payload"}, {"id": 743892225, "item_id": 46493264, "url": "https://news.ycombinator.com/item?id=46493264", "by": "larusso", "date": "2026-01-04", "version": null, "stance": "warn", "quote": "The thiserror crate makes it too easy to just foreward errors", "excerpt": "Error handling in rust is the number one frustration. I rewrote my errors multiple time. I used error_chain which looked good on paper but was just as broken as thiserror and anyhow. The missing piece is already the fact that no one really defines how to write good and meaningful error types for the different audiences. Even the article described some cases that are highly implementation specific. I will take a look ", "context": "Rust developer", "use_case": "Rust error handling", "switched_from": "", "story": "Stop Forwarding Errors, Start Designing Them"}, {"id": 742778528, "item_id": 46423658, "url": "https://news.ycombinator.com/item?id=46423658", "by": "fauigerzigerk", "date": "2025-12-29", "version": null, "stance": "warn", "quote": "thiserror actually encourages this sort of implementation leak:", "excerpt": ">I usually don't try to imagine how someone should handle the error. But that's exactly what you do when you... >... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to", "context": "", "use_case": "Rust error derive macros", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 742659360, "item_id": 46416210, "url": "https://news.ycombinator.com/item?id=46416210", "by": "epage", "date": "2025-12-28", "version": null, "stance": "warn", "quote": "Take the example at https://docs.rs/thiserror/latest/thiserror/", "excerpt": "Take the example at https://docs.rs/thiserror/latest/thiserror/ - Struct variant fields are public, limiting how you evolve the fields and types - Struct variants need non_exhaustive - It shows using `from` on an error. What happens if you want to include more context? Or change your impl which can change the source error type None of this is syntactically unique to errors. This becomes people's first thought of what", "context": "", "use_case": "", "switched_from": "", "story": "Rust Errors Without Dependencies"}]}], "who": [], "tags": [], "use_cases": ["rust error types", "rust error handling", "library error types", "derive error types", "defining rust error types", "rust error derive macros"], "compared": [{"slug": "anyhow", "name": "anyhow", "co": 13, "switched_from": 0, "switched_to": 0}], "makers": [], "threads": [{"url": "https://news.ycombinator.com/item?id=46408365", "title": "Rust Errors Without Dependencies", "mentions": 5}, {"url": "https://news.ycombinator.com/item?id=48259808", "title": "Migrating from Go to Rust", "mentions": 3}, {"url": "https://news.ycombinator.com/item?id=46491051", "title": "Stop Forwarding Errors, Start Designing Them", "mentions": 2}, {"url": "https://news.ycombinator.com/item?id=49374269", "title": "Malicious Rust Crate Arrayref Runs a Build-Time Payload", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=47490648", "title": "An Incoherent Rust", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=46854088", "title": "RMA \u2013 Fast Rust monorepo scanner cross-file taint, typestate, <0.5s on 100k LOC", "mentions": 1}], "sentiment_by_month": {"2025-11": {"neutral": 1, "warn": 1}, "2025-12": {"warn": 4, "recommend": 1}, "2026-01": {"warn": 1, "recommend": 2}, "2026-02": {"recommend": 1}, "2026-03": {"neutral": 1}, "2026-04": {}, "2026-05": {"recommend": 2}, "2026-06": {}, "2026-07": {}, "2026-08": {"warn": 1}, "2026-09": {}, "2026-10": {}}, "versions": [], "version_unnamed": 0, "family_ref": null, "runs_on": null, "lines": [], "quotes": [{"id": 790084290, "item_id": 49380268, "url": "https://news.ycombinator.com/item?id=49380268", "by": "echelon", "date": "2026-08-20", "version": null, "stance": "warn", "quote": "I wouldn't want to see anyhow, thiserror, anything opinionated", "excerpt": "Good ideas are pulled into the standard library. https://crates.io/crates/once_cell https://doc.rust-lang.org/std/cell/struct.OnceCell.html Not everything should be eligible for this treatment. Certainly not an HTTP library or something without extremely widespread applicability. Nearly all of my projects used once_cell, so it's good to see that pulled in. I wouldn't want to see anyhow, thiserror, anything opinionate", "context": "", "use_case": "", "switched_from": "", "story": "Malicious Rust Crate Arrayref Runs a Build-Time Payload"}, {"id": 772195136, "item_id": 48262196, "url": "https://news.ycombinator.com/item?id=48262196", "by": "ViewTrick1002", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "The example on the docs page is quite clear", "excerpt": "How come you get macro expansion errors? Or is it because you write incorrect syntax in the enum error definitions? The example on the docs page is quite clear: https://docs.rs/thiserror/latest/thiserror/#example Including all kinds of errors: Strings, tagged unions and automatically converting from std::io::Error with added context. That one page document is the entire documentation for the thiserror crate.", "context": "", "use_case": "Rust error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 772190320, "item_id": 48261895, "url": "https://news.ycombinator.com/item?id=48261895", "by": "LoganDark", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "I use thiserror a lot to help with my impls.", "excerpt": "thiserror and anyhow are just std::error with extra steps. Note that io::error is just a specific std::error. The entire point in Rust is that you wrap Error impls with other Error impls, or translate one impl into another using a match. I've found this is far more flexible and verifiable than most other languages, because if you craft your error types with enough rigor, you can basically have a complete semantic bac", "context": "", "use_case": "Rust error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 772179105, "item_id": 48261194, "url": "https://news.ycombinator.com/item?id=48261194", "by": "ViewTrick1002", "date": "2026-05-24", "version": null, "stance": "recommend", "quote": "thiserror for libraries, helping you create the standard library error types", "excerpt": "They all convert seamlessly, and the enums make the branches explicit. Don't even need to check the documentation to find which errors supposedly exists like in Go with its errors.Is, errors.As, wrapping and what not. An easy rule before you make a knowledge based choice is thiserror for libraries, helping you create the standard library error types and anyhow for applications, easy strings you bubble up. Or just go ", "context": "", "use_case": "library error types", "switched_from": "", "story": "Migrating from Go to Rust"}, {"id": 760653857, "item_id": 47540866, "url": "https://news.ycombinator.com/item?id=47540866", "by": "uzerfcwn", "date": "2026-03-27", "version": null, "stance": "neutral", "quote": "even with thiserror handling some stuff like the From traits", "excerpt": "I don't know what quotemstr was specifically talking about, but here's my own take. The ideal error handling is inferred algebraic effects like in Koka[1]. This allows you to add a call to an error-throwing function 15 layers down the stack and it's automatically propagated into the type signatures of all functions up the stack (and you can see the inferred effects with a language server or other tooling, similar to ", "context": "", "use_case": "Derive error types", "switched_from": "", "story": "An Incoherent Rust"}, {"id": 750598880, "item_id": 46912430, "url": "https://news.ycombinator.com/item?id=46912430", "by": "bumahkib7", "date": "2026-02-06", "version": null, "stance": "recommend", "quote": "A single crate level errors.rs with thiserror makes big repos feel way less messy.", "excerpt": "This is super interesting. The \u201cmake everything look the same\u201d angle is exactly what AI generated monorepos need if you want reviews to stay sane. The absolute paths rule and the \u201cno cycles unless same module\u201d rule are both clean. I like that you\u2019re optimizing for navigation too, not just style. The two \u201cwould be nice\u201d points hit hard: A single crate level errors.rs with thiserror makes big repos feel way less messy.", "context": "", "use_case": "", "switched_from": "", "story": "RMA \u2013 Fast Rust monorepo scanner cross-file taint, typestate, <0.5s on 100k LOC"}, {"id": 744789824, "item_id": 46549364, "url": "https://news.ycombinator.com/item?id=46549364", "by": "bccdee", "date": "2026-01-08", "version": null, "stance": "recommend", "quote": "thiserror\u00b9 for libraries, anyhow\u00b2 for applications", "excerpt": "> There is good reason why even the languages that support defined error sets have trended back to using open-ended constructs. Rust does it that way & has never trended in any other direction. The generally-accepted wisdom is \"thiserror\u00b9 for libraries, anyhow\u00b2 for applications\"\u2014i.e., any error that's liable to be handled by a machine should be an enum of exhaustively-matchable error kinds, whereas anything that's ju", "context": "", "use_case": "Rust error handling", "switched_from": "", "story": "An Honest Review of Go"}, {"id": 743910993, "item_id": 46494437, "url": "https://news.ycombinator.com/item?id=46494437", "by": "tison", "date": "2026-01-04", "version": null, "stance": "recommend", "quote": "we have been using thiserror + exn for a long time, and it works well", "excerpt": "I think they are almost compatible. `thiserror` helps you define the error type. That error type can then be used with `anyhow` or `exn`. Actually, we have been using thiserror + exn for a long time, and it works well. While later we realize that `struct ModuleError(String)` can easily implement Error without thiserror, we remove thiserror dependency for conciseness. `exn` can use `anyhow::Error` as its inner Error. ", "context": "", "use_case": "defining Rust error types", "switched_from": "", "story": "Stop Forwarding Errors, Start Designing Them"}, {"id": 743892225, "item_id": 46493264, "url": "https://news.ycombinator.com/item?id=46493264", "by": "larusso", "date": "2026-01-04", "version": null, "stance": "warn", "quote": "The thiserror crate makes it too easy to just foreward errors", "excerpt": "Error handling in rust is the number one frustration. I rewrote my errors multiple time. I used error_chain which looked good on paper but was just as broken as thiserror and anyhow. The missing piece is already the fact that no one really defines how to write good and meaningful error types for the different audiences. Even the article described some cases that are highly implementation specific. I will take a look ", "context": "Rust developer", "use_case": "Rust error handling", "switched_from": "", "story": "Stop Forwarding Errors, Start Designing Them"}, {"id": 742778528, "item_id": 46423658, "url": "https://news.ycombinator.com/item?id=46423658", "by": "fauigerzigerk", "date": "2025-12-29", "version": null, "stance": "warn", "quote": "thiserror actually encourages this sort of implementation leak:", "excerpt": ">I usually don't try to imagine how someone should handle the error. But that's exactly what you do when you... >... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to", "context": "", "use_case": "Rust error derive macros", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 742659360, "item_id": 46416210, "url": "https://news.ycombinator.com/item?id=46416210", "by": "epage", "date": "2025-12-28", "version": null, "stance": "warn", "quote": "Take the example at https://docs.rs/thiserror/latest/thiserror/", "excerpt": "Take the example at https://docs.rs/thiserror/latest/thiserror/ - Struct variant fields are public, limiting how you evolve the fields and types - Struct variants need non_exhaustive - It shows using `from` on an error. What happens if you want to include more context? Or change your impl which can change the source error type None of this is syntactically unique to errors. This becomes people's first thought of what", "context": "", "use_case": "", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 742642785, "item_id": 46415174, "url": "https://news.ycombinator.com/item?id=46415174", "by": "burntsushi", "date": "2025-12-28", "version": null, "stance": "recommend", "quote": "If you're using a library like `thiserror`, then it's much less likely.", "excerpt": "> I do think that `std::error::Error` is mostly pointless. That's a value judgment, and reasonable people can disagree. I took it as a statement of fact. It is a factual matter of whether `std::error::Error` has a point to it or not. And it definitively does. I use the error chain in just about every CLI application I've built. It's not even mostly pointless. It's incredibly useful and it provides an interoperable po", "context": "", "use_case": "", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 742632561, "item_id": 46414535, "url": "https://news.ycombinator.com/item?id=46414535", "by": "burntsushi", "date": "2025-12-28", "version": null, "stance": "recommend", "quote": "anyhow` and `thiserror` have been around for a number of years now and shows no signs of going away", "excerpt": "> It was `std` only and linked to a concept of backtraces, which made it a non-started for embedded. It just seemed to me that it was a bad idea ever to use it in a library and that it would harm embedded users. It was never linked to backtraces. And if you used `std::error::Error` in a library that you also wanted to support in no-std mode, then you just didn't implement the `std::error::Error` trait when the `std` ", "context": "", "use_case": "", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 742630290, "item_id": 46414393, "url": "https://news.ycombinator.com/item?id=46414393", "by": "osiris88", "date": "2025-12-28", "version": null, "stance": "warn", "quote": "Nowadays I try to avoid all of these libraries (failure, anyhow, thiserror, etc.)", "excerpt": "I've been using rust for 8+ years, I remember the experiments around `failure` crate, a precursor to anyhow if I remember right... and then eyre, and then thiserror... It just felt like too much churn and each one offered barely any distinction to the previous. Additionally, the `std::error::Error` trait was very poorly designed when it was initially created. It was `std` only and linked to a concept of backtraces, w", "context": "", "use_case": "", "switched_from": "", "story": "Rust Errors Without Dependencies"}, {"id": 738496834, "item_id": 46156052, "url": "https://news.ycombinator.com/item?id=46156052", "by": "nu11ptr", "date": "2025-12-04", "version": null, "stance": "warn", "quote": "I don't think `thiserror` and `anyhow` with their libraries vs applications distinction makes a lot of sense.", "excerpt": "> you sort of come to understand \"this goo at the end of the expression is just coercing the return value into whatever alternate goo the function signature dictates it needs\", which is not at all the same thing as careful error handling. I think the problem is Rust does a great job at providing the basic mechanics of errors, but then stops a bit short. First, I didn't realize until relatively recently that any `Stri", "context": "", "use_case": "", "switched_from": "", "story": "Thoughts on Go vs. Rust vs. Zig"}, {"id": 736901873, "item_id": 46056367, "url": "https://news.ycombinator.com/item?id=46056367", "by": "dlahoda", "date": "2025-11-26", "version": null, "stance": "warn", "quote": "not thiserror", "excerpt": "end result is here https://zo-devnet.n1.xyz/docs - well documented strongly typed errors for API. most eveolved https://zo-devnet.n1.xyz/docs#tag/default/post/action - mixes binary encoding, headers, and numeric errors embeeding (http goes to binary tx format). all strongly typed without duplicated boilerplate. inside - ad hoc error assembly - display_doc,derive_more, backtrace - no anyhow, not thiserror, no snafu. f", "context": "", "use_case": "", "switched_from": "", "story": "Implementing Rust newtype for errors in axum"}, {"id": 734754611, "item_id": 45922163, "url": "https://news.ycombinator.com/item?id=45922163", "by": "virexdev", "date": "2025-11-13", "version": null, "stance": "neutral", "quote": "taught me a lot about thiserror / anyhow and why good context matters", "excerpt": "FAQ [?] why did you make this? [!] i wanted a small, fast, rust-based tree-like tool that was actually fun to build and mess with. while working on it i hit a bunch of interesting challenges: ownership issues, error handling, unicode alignment, and even building a simple interactive terminal UI. this is mostly a hobby project, but i think it\u2019s a nice little learning playground too. [?] what makes it interesting? [X] ", "context": "", "use_case": "", "switched_from": "", "story": "Canopy It's a fast rust CLI that prints directory trees"}]}