Should I avoid unwrap in production application?

There are two questions folded into one here:

  • is the use of panic! acceptable in production
  • is the use of unwrap acceptable in production

panic! is a tool that is used, in Rust, to signal irrecoverable situations/violated assumptions. It can be used to either crash a program that cannot possibly continue in the face of this failure (for example, OOM situation) or to work around the compiler knowing it cannot be executed (at the moment).

unwrap is a convenience, that is best avoided in production. The problem about unwrap is that it does not state which assumption was violated, it is better instead to use expect("") which is functionally equivalent but will also give a clue as to what went wrong (without opening the source code).


While the whole “error handling”-topic is very complicated and often opinion based, this question can actually be answered here, because Rust has rather narrow philosophy. That is:

  • panic! for programming errors (“bugs”)
  • proper error propagation and handling with Result<T, E> and Option<T> for expected and recoverable errors

One can think of unwrap() as converting between those two kinds of errors (it is converting a recoverable error into a panic!()). When you write unwrap() in your program, you are saying:

At this point, a None/Err(_) value is a programming error and the program is unable to recover from it.


For example, say you are working with a HashMap and want to insert a value which you may want to mutate later:

age_map.insert("peter", 21);
// ...

if /* some condition */ {
    *age_map.get_mut("peter").unwrap() += 1;
}

Here we use the unwrap(), because we can be sure that the key holds a value. It would be a programming error if it didn't and even more important: it's not really recoverable. What would you do when at that point there is no value with the key "peter"? Try inserting it again ... ?

But as you may know, there is a beautiful entry API for the maps in Rust's standard library. With that API you can avoid all those unwrap()s. And this applies to pretty much all situations: you can very often restructure your code to avoid the unwrap()! Only in a very few situation there is no way around it. But then it's OK to use it, if you want to signal: at this point, it would be a programming bug.


There has been a recent, fairly popular blog post on the topic of “error handling” whose conclusion is similar to Rust's philosophy. It's rather long but worth reading: “The Error Model”. Here is my try on summarizing the article in relation to this question:

  • deliberately distinguish between programming bugs and recoverable errors
  • use a “fail fast” approach for programming bugs

In summary: use unwrap() when you are sure that the recoverable error that you get is in fact unrecoverable at that point. Bonus points for explaining “why?” in a comment above the affected line ;-)


unwrap() is not necessarily dangerous. Just like with unreachable!() there are cases where you can be sure some condition will not be triggered.

Functions returning Option or Result are sometimes just suited to a wider range of conditions, but due to how your program is structured those cases might never occur.

For example: when you create an iterator from a Vector you buid yourself, you know its exact length and can be sure how long invoking next() on it returns a Some<T> (and you can safely unwrap() it).


In other words, can I say my program is reliable if I use unwrap? Or must I avoid unwrap even if the case seems simple?

I think using unwrap judiciously is something you have to learn to handle, it can't just be avoided.

My rhetorical question barrage would be:

  1. Can I say my program is reliable if I use indexing on vectors, arrays or slices?
  2. Can I say my program is reliable if I use integer division?
  3. Can I say my program is reliable if I add numbers?

(1) is like unwrap, indexing panics if you make a contract violation and try to index out of bounds. This would be a bug in the program, but it doesn't catch as much attention as a call to unwrap.

(2) is like unwrap, integer division panics if the divisor is zero.

(3) is unlike unwrap, addition does not check for overflow in release builds, so it may silently result in wraparound and logical errors.

Of course, there are strategies for handling all of these without leaving panicky cases in the code, but many programs simply use for example bounds checking as it is.