diff --git a/exercises/advanced_errors/advanced_errs1.rs b/exercises/advanced_errors/advanced_errs1.rs
new file mode 100644
index 0000000..4bc7b63
--- /dev/null
+++ b/exercises/advanced_errors/advanced_errs1.rs
@@ -0,0 +1,98 @@
+// advanced_errs1.rs
+
+// Remember back in errors6, we had multiple mapping functions so that we
+// could translate lower-level errors into our custom error type using
+// `map_err()`? What if we could use the `?` operator directly instead?
+
+// Make this code compile! Execute `rustlings hint advanced_errs1` for
+// hints :)
+
+// I AM NOT DONE
+
+use std::num::ParseIntError;
+use std::str::FromStr;
+
+// This is a custom error type that we will be using in the `FromStr`
+// implementation.
+#[derive(PartialEq, Debug)]
+enum ParsePosNonzeroError {
+    Creation(CreationError),
+    ParseInt(ParseIntError),
+}
+
+impl From<CreationError> for ParsePosNonzeroError {
+    fn from(e: CreationError) -> Self {
+        // TODO: complete this implementation so that the `?` operator will
+        // work for `CreationError`
+    }
+}
+
+// TODO: implement another instance of the `From` trait here so that the
+// `?` operator will work in the other place in the `FromStr`
+// implementation below.
+
+// Don't change anything below this line.
+
+impl FromStr for PositiveNonzeroInteger {
+    type Err = ParsePosNonzeroError;
+    fn from_str(s: &str) -> Result<PositiveNonzeroInteger, Self::Err> {
+        let x: i64 = s.parse()?;
+        Ok(PositiveNonzeroInteger::new(x)?)
+    }
+}
+
+#[derive(PartialEq, Debug)]
+struct PositiveNonzeroInteger(u64);
+
+#[derive(PartialEq, Debug)]
+enum CreationError {
+    Negative,
+    Zero,
+}
+
+impl PositiveNonzeroInteger {
+    fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
+        match value {
+            x if x < 0 => Err(CreationError::Negative),
+            x if x == 0 => Err(CreationError::Zero),
+            x => Ok(PositiveNonzeroInteger(x as u64)),
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_parse_error() {
+        // We can't construct a ParseIntError, so we have to pattern match.
+        assert!(matches!(
+            PositiveNonzeroInteger::from_str("not a number"),
+            Err(ParsePosNonzeroError::ParseInt(_))
+        ));
+    }
+
+    #[test]
+    fn test_negative() {
+        assert_eq!(
+            PositiveNonzeroInteger::from_str("-555"),
+            Err(ParsePosNonzeroError::Creation(CreationError::Negative))
+        );
+    }
+
+    #[test]
+    fn test_zero() {
+        assert_eq!(
+            PositiveNonzeroInteger::from_str("0"),
+            Err(ParsePosNonzeroError::Creation(CreationError::Zero))
+        );
+    }
+
+    #[test]
+    fn test_positive() {
+        let x = PositiveNonzeroInteger::new(42);
+        assert!(x.is_ok());
+        assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap()));
+    }
+}
diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs
new file mode 100644
index 0000000..d9d44d0
--- /dev/null
+++ b/exercises/advanced_errors/advanced_errs2.rs
@@ -0,0 +1,203 @@
+// advanced_errs2.rs
+
+// This exercise demonstrates a few traits that are useful for custom error
+// types to implement, especially so that other code can consume the custom
+// error type more usefully.
+
+// Make this compile, and make the tests pass!
+// Execute `rustlings hint advanced_errs2` for hints.
+
+// Steps:
+// 1. Implement a missing trait so that `main()` will compile.
+// 2. Complete the partial implementation of `From` for
+//    `ParseClimateError`.
+// 3. Handle the missing error cases in the `FromStr` implementation for
+//    `Climate`.
+// 4. Complete the partial implementation of `Display` for
+//    `ParseClimateError`.
+
+// I AM NOT DONE
+
+use std::error::Error;
+use std::fmt::{self, Display, Formatter};
+use std::num::{ParseFloatError, ParseIntError};
+use std::str::FromStr;
+
+// This is the custom error type that we will be using for the parser for
+// `Climate`.
+#[derive(Debug, PartialEq)]
+enum ParseClimateError {
+    Empty,
+    BadLen,
+    NoCity,
+    ParseInt(ParseIntError),
+    ParseFloat(ParseFloatError),
+}
+
+// This `From` implementation allows the `?` operator to work on
+// `ParseIntError` values.
+impl From<ParseIntError> for ParseClimateError {
+    fn from(e: ParseIntError) -> Self {
+        Self::ParseInt(e)
+    }
+}
+
+// This `From` implementation allows the `?` operator to work on
+// `ParseFloatError` values.
+impl From<ParseFloatError> for ParseClimateError {
+    fn from(e: ParseFloatError) -> Self {
+        // TODO: Complete this function
+    }
+}
+
+// TODO: Implement a missing trait so that `main()` below will compile. It
+// is not necessary to implement any methods inside the missing trait.
+
+// The `Display` trait allows for other code to obtain the error formatted
+// as a user-visible string.
+impl Display for ParseClimateError {
+    // TODO: Complete this function so that it produces the correct strings
+    // for each error variant.
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        // Imports the variants to make the following code more compact.
+        use ParseClimateError::*;
+        match self {
+            NoCity => write!(f, "no city name"),
+            ParseFloat(e) => write!(f, "error parsing temperature: {}", e),
+            _ => write!(f, "unhandled error!"),
+        }
+    }
+}
+
+#[derive(Debug, PartialEq)]
+struct Climate {
+    city: String,
+    year: u32,
+    temp: f32,
+}
+
+// Parser for `Climate`.
+// 1. Split the input string into 3 fields: city, year, temp.
+// 2. Return an error if the string is empty or has the wrong number of
+//    fields.
+// 3. Return an error if the city name is empty.
+// 4. Parse the year as a `u32` and return an error if that fails.
+// 5. Parse the temp as a `f32` and return an error if that fails.
+// 6. Return an `Ok` value containing the completed `Climate` value.
+impl FromStr for Climate {
+    type Err = ParseClimateError;
+    // TODO: Complete this function by making it handle the missing error
+    // cases.
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let v: Vec<_> = s.split(',').collect();
+        let (city, year, temp) = match &v[..] {
+            [city, year, temp] => (city.to_string(), year, temp),
+            _ => return Err(ParseClimateError::BadLen),
+        };
+        let year: u32 = year.parse()?;
+        let temp: f32 = temp.parse()?;
+        Ok(Climate { city, year, temp })
+    }
+}
+
+// Don't change anything below this line (other than to enable ignored
+// tests).
+
+fn main() -> Result<(), Box<dyn Error>> {
+    println!("{:?}", "Hong Kong,1999,25.7".parse::<Climate>()?);
+    println!("{:?}", "".parse::<Climate>()?);
+    Ok(())
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    #[test]
+    fn test_empty() {
+        let res = "".parse::<Climate>();
+        assert_eq!(res, Err(ParseClimateError::Empty));
+        assert_eq!(res.unwrap_err().to_string(), "empty input");
+    }
+    #[test]
+    fn test_short() {
+        let res = "Boston,1991".parse::<Climate>();
+        assert_eq!(res, Err(ParseClimateError::BadLen));
+        assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
+    }
+    #[test]
+    fn test_long() {
+        let res = "Paris,1920,17.2,extra".parse::<Climate>();
+        assert_eq!(res, Err(ParseClimateError::BadLen));
+        assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
+    }
+    #[test]
+    fn test_no_city() {
+        let res = ",1997,20.5".parse::<Climate>();
+        assert_eq!(res, Err(ParseClimateError::NoCity));
+        assert_eq!(res.unwrap_err().to_string(), "no city name");
+    }
+    #[test]
+    fn test_parse_int_neg() {
+        let res = "Barcelona,-25,22.3".parse::<Climate>();
+        assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+        let err = res.unwrap_err();
+        if let ParseClimateError::ParseInt(ref inner) = err {
+            assert_eq!(
+                err.to_string(),
+                format!("error parsing year: {}", inner.to_string())
+            );
+        } else {
+            unreachable!();
+        };
+    }
+    #[test]
+    fn test_parse_int_bad() {
+        let res = "Beijing,foo,15.0".parse::<Climate>();
+        assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+        let err = res.unwrap_err();
+        if let ParseClimateError::ParseInt(ref inner) = err {
+            assert_eq!(
+                err.to_string(),
+                format!("error parsing year: {}", inner.to_string())
+            );
+        } else {
+            unreachable!();
+        };
+    }
+    #[test]
+    fn test_parse_float() {
+        let res = "Manila,2001,bar".parse::<Climate>();
+        assert!(matches!(res, Err(ParseClimateError::ParseFloat(_))));
+        let err = res.unwrap_err();
+        if let ParseClimateError::ParseFloat(ref inner) = err {
+            assert_eq!(
+                err.to_string(),
+                format!("error parsing temperature: {}", inner.to_string())
+            );
+        } else {
+            unreachable!();
+        };
+    }
+    #[test]
+    fn test_parse_good() {
+        let res = "Munich,2015,23.1".parse::<Climate>();
+        assert_eq!(
+            res,
+            Ok(Climate {
+                city: "Munich".to_string(),
+                year: 2015,
+                temp: 23.1,
+            })
+        );
+    }
+    #[test]
+    #[ignore]
+    fn test_downcast() {
+        let res = "São Paulo,-21,28.5".parse::<Climate>();
+        assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
+        let err = res.unwrap_err();
+        let inner: Option<&(dyn Error + 'static)> = err.source();
+        assert!(inner.is_some());
+        assert!(inner.unwrap().is::<ParseIntError>());
+    }
+}
diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs
index 4beebac..6e9e699 100644
--- a/exercises/conversions/from_str.rs
+++ b/exercises/conversions/from_str.rs
@@ -1,16 +1,31 @@
-// This does practically the same thing that TryFrom<&str> does.
+// from_str.rs
+// This is similar to from_into.rs, but this time we'll implement `FromStr`
+// and return errors instead of falling back to a default value.
 // Additionally, upon implementing FromStr, you can use the `parse` method
 // on strings to generate an object of the implementor type.
 // You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
-use std::error;
+use std::num::ParseIntError;
 use std::str::FromStr;
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 struct Person {
     name: String,
     age: usize,
 }
 
+// We will use this error type for the `FromStr` implementation.
+#[derive(Debug, PartialEq)]
+enum ParsePersonError {
+    // Empty input string
+    Empty,
+    // Incorrect number of fields
+    BadLen,
+    // Empty name field
+    NoName,
+    // Wrapped error from parse::<usize>()
+    ParseInt(ParseIntError),
+}
+
 // I AM NOT DONE
 
 // Steps:
@@ -24,7 +39,7 @@ struct Person {
 // If everything goes well, then return a Result of a Person object
 
 impl FromStr for Person {
-    type Err = Box<dyn error::Error>;
+    type Err = ParsePersonError;
     fn from_str(s: &str) -> Result<Person, Self::Err> {
     }
 }
@@ -40,7 +55,7 @@ mod tests {
 
     #[test]
     fn empty_input() {
-        assert!("".parse::<Person>().is_err());
+        assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
     }
     #[test]
     fn good_input() {
@@ -52,41 +67,56 @@ mod tests {
     }
     #[test]
     fn missing_age() {
-        assert!("John,".parse::<Person>().is_err());
+        assert!(matches!(
+            "John,".parse::<Person>(),
+            Err(ParsePersonError::ParseInt(_))
+        ));
     }
 
     #[test]
     fn invalid_age() {
-        assert!("John,twenty".parse::<Person>().is_err());
+        assert!(matches!(
+            "John,twenty".parse::<Person>(),
+            Err(ParsePersonError::ParseInt(_))
+        ));
     }
 
     #[test]
     fn missing_comma_and_age() {
-        assert!("John".parse::<Person>().is_err());
+        assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
     }
 
     #[test]
     fn missing_name() {
-        assert!(",1".parse::<Person>().is_err());
+        assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
     }
 
     #[test]
     fn missing_name_and_age() {
-        assert!(",".parse::<Person>().is_err());
+        assert!(matches!(
+            ",".parse::<Person>(),
+            Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+        ));
     }
 
     #[test]
     fn missing_name_and_invalid_age() {
-        assert!(",one".parse::<Person>().is_err());
+        assert!(matches!(
+            ",one".parse::<Person>(),
+            Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+        ));
     }
 
     #[test]
     fn trailing_comma() {
-        assert!("John,32,".parse::<Person>().is_err());
+        assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
     }
 
     #[test]
     fn trailing_comma_and_some_string() {
-        assert!("John,32,man".parse::<Person>().is_err());
+        assert_eq!(
+            "John,32,man".parse::<Person>(),
+            Err(ParsePersonError::BadLen)
+        );
     }
 }
diff --git a/exercises/conversions/try_from_into.rs b/exercises/conversions/try_from_into.rs
index c0b5d98..b8ec445 100644
--- a/exercises/conversions/try_from_into.rs
+++ b/exercises/conversions/try_from_into.rs
@@ -1,9 +1,9 @@
+// try_from_into.rs
 // TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
 // Basically, this is the same as From. The main difference is that this should return a Result type
 // instead of the target type itself.
 // You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
 use std::convert::{TryFrom, TryInto};
-use std::error;
 
 #[derive(Debug, PartialEq)]
 struct Color {
@@ -12,12 +12,21 @@ struct Color {
     blue: u8,
 }
 
+// We will use this error type for these `TryFrom` conversions.
+#[derive(Debug, PartialEq)]
+enum IntoColorError {
+    // Incorrect length of slice
+    BadLen,
+    // Integer conversion error
+    IntConversion,
+}
+
 // I AM NOT DONE
 
 // Your task is to complete this implementation
 // and return an Ok result of inner type Color.
 // You need to create an implementation for a tuple of three integers,
-// an array of three integers and a slice of integers.
+// an array of three integers, and a slice of integers.
 //
 // Note that the implementation for tuple and array will be checked at compile time,
 // but the slice implementation needs to check the slice length!
@@ -25,20 +34,23 @@ struct Color {
 
 // Tuple implementation
 impl TryFrom<(i16, i16, i16)> for Color {
-    type Error = Box<dyn error::Error>;
-    fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}
+    type Error = IntoColorError;
+    fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
+    }
 }
 
 // Array implementation
 impl TryFrom<[i16; 3]> for Color {
-    type Error = Box<dyn error::Error>;
-    fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
+    type Error = IntoColorError;
+    fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
+    }
 }
 
 // Slice implementation
 impl TryFrom<&[i16]> for Color {
-    type Error = Box<dyn error::Error>;
-    fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
+    type Error = IntoColorError;
+    fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
+    }
 }
 
 fn main() {
@@ -46,15 +58,15 @@ fn main() {
     let c1 = Color::try_from((183, 65, 14));
     println!("{:?}", c1);
 
-    // Since From is implemented for Color, we should be able to use Into
+    // Since TryFrom is implemented for Color, we should be able to use TryInto
     let c2: Result<Color, _> = [183, 65, 14].try_into();
     println!("{:?}", c2);
 
     let v = vec![183, 65, 14];
-    // With slice we should use `from` function
+    // With slice we should use `try_from` function
     let c3 = Color::try_from(&v[..]);
     println!("{:?}", c3);
-    // or take slice within round brackets and use Into
+    // or take slice within round brackets and use TryInto
     let c4: Result<Color, _> = (&v[..]).try_into();
     println!("{:?}", c4);
 }
@@ -65,15 +77,24 @@ mod tests {
 
     #[test]
     fn test_tuple_out_of_range_positive() {
-        assert!(Color::try_from((256, 1000, 10000)).is_err());
+        assert_eq!(
+            Color::try_from((256, 1000, 10000)),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_tuple_out_of_range_negative() {
-        assert!(Color::try_from((-1, -10, -256)).is_err());
+        assert_eq!(
+            Color::try_from((-1, -10, -256)),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_tuple_sum() {
-        assert!(Color::try_from((-1, 255, 255)).is_err());
+        assert_eq!(
+            Color::try_from((-1, 255, 255)),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_tuple_correct() {
@@ -91,17 +112,17 @@ mod tests {
     #[test]
     fn test_array_out_of_range_positive() {
         let c: Result<Color, _> = [1000, 10000, 256].try_into();
-        assert!(c.is_err());
+        assert_eq!(c, Err(IntoColorError::IntConversion));
     }
     #[test]
     fn test_array_out_of_range_negative() {
         let c: Result<Color, _> = [-10, -256, -1].try_into();
-        assert!(c.is_err());
+        assert_eq!(c, Err(IntoColorError::IntConversion));
     }
     #[test]
     fn test_array_sum() {
         let c: Result<Color, _> = [-1, 255, 255].try_into();
-        assert!(c.is_err());
+        assert_eq!(c, Err(IntoColorError::IntConversion));
     }
     #[test]
     fn test_array_correct() {
@@ -119,17 +140,26 @@ mod tests {
     #[test]
     fn test_slice_out_of_range_positive() {
         let arr = [10000, 256, 1000];
-        assert!(Color::try_from(&arr[..]).is_err());
+        assert_eq!(
+            Color::try_from(&arr[..]),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_slice_out_of_range_negative() {
         let arr = [-256, -1, -10];
-        assert!(Color::try_from(&arr[..]).is_err());
+        assert_eq!(
+            Color::try_from(&arr[..]),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_slice_sum() {
         let arr = [-1, 255, 255];
-        assert!(Color::try_from(&arr[..]).is_err());
+        assert_eq!(
+            Color::try_from(&arr[..]),
+            Err(IntoColorError::IntConversion)
+        );
     }
     #[test]
     fn test_slice_correct() {
@@ -148,11 +178,11 @@ mod tests {
     #[test]
     fn test_slice_excess_length() {
         let v = vec![0, 0, 0, 0];
-        assert!(Color::try_from(&v[..]).is_err());
+        assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
     }
     #[test]
     fn test_slice_insufficient_length() {
         let v = vec![0, 0];
-        assert!(Color::try_from(&v[..]).is_err());
+        assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
     }
 }
diff --git a/info.toml b/info.toml
index afc7fdf..b91d109 100644
--- a/info.toml
+++ b/info.toml
@@ -936,6 +936,27 @@ mode = "test"
 hint = """
 Follow the steps provided right before the `From` implementation"""
 
+[[exercises]]
+name = "from_str"
+path = "exercises/conversions/from_str.rs"
+mode = "test"
+hint = """
+The implementation of FromStr should return an Ok with a Person object,
+or an Err with an error if the string is not valid.
+
+This is almost like the `from_into` exercise, but returning errors instead
+of falling back to a default value.
+
+Hint: Look at the test cases to see which error variants to return.
+
+Another hint: You can use the `map_err` method of `Result` with a function
+or a closure to wrap the error from `parse::<usize>`.
+
+Yet another hint: If you would like to propagate errors by using the `?`
+operator in your solution, you might want to look at
+https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html
+"""
+
 [[exercises]]
 name = "try_from_into"
 path = "exercises/conversions/try_from_into.rs"
@@ -944,17 +965,19 @@ hint = """
 Follow the steps provided right before the `TryFrom` implementation.
 You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
 
-You might want to look back at the exercise errors5 (or its hints) to remind
-yourself about how `Box<dyn Error>` works.
+Hint: Is there an implementation of `TryFrom` in the standard library that
+can both do the required integer conversion and check the range of the input?
 
-If you're trying to return a string as an error, note that neither `str`
-nor `String` implements `error::Error`. However, there is an implementation
-of `From<&str>` for `Box<dyn Error>`. This means you can use `.into()` or
-the `?` operator to convert your string into the correct error type.
+Another hint: Look at the test cases to see which error variants to return.
 
-If you're having trouble with using the `?` operator to convert an error string,
-recall that `?` works to convert `Err(something)` into the appropriate error
-type for returning from the function."""
+Yet another hint: You can use the `map_err` or `or` methods of `Result` to
+convert errors.
+
+Yet another hint: If you would like to propagate errors by using the `?`
+operator in your solution, you might want to look at
+https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html
+
+Challenge: Can you make the `TryFrom` implementations generic over many integer types?"""
 
 [[exercises]]
 name = "as_ref_mut"
@@ -963,14 +986,54 @@ mode = "test"
 hint = """
 Add AsRef<str> as a trait bound to the functions."""
 
+# ADVANCED ERRORS
+
 [[exercises]]
-name = "from_str"
-path = "exercises/conversions/from_str.rs"
+name = "advanced_errs1"
+path = "exercises/advanced_errors/advanced_errs1.rs"
 mode = "test"
 hint = """
-The implementation of FromStr should return an Ok with a Person object,
-or an Err with an error if the string is not valid.
-This is almost like the `try_from_into` exercise.
+This exercise uses an updated version of the code in errors6. The parsing
+code is now in an implementation of the `FromStr` trait. Note that the
+parsing code uses `?` directly, without any calls to `map_err()`. There is
+one partial implementation of the `From` trait example that you should
+complete.
 
-If you're having trouble with returning the correct error type, see the
-hints for try_from_into."""
+Details: The `?` operator calls `From::from()` on the error type to convert
+it to the error type of the return type of the surrounding function.
+
+Hint: You will need to write another implementation of `From` that has a
+different input type.
+"""
+
+[[exercises]]
+name = "advanced_errs2"
+path = "exercises/advanced_errors/advanced_errs2.rs"
+mode = "test"
+hint = """
+This exercise demonstrates a few traits that are useful for custom error
+types to implement. These traits make it easier for other code to consume
+the custom error type.
+
+Follow the steps in the comment near the top of the file. You will have to
+supply a missing trait implementation, and complete a few incomplete ones.
+
+You may find these pages to be helpful references:
+https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/define_error_type.html
+https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html
+https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/wrap_error.html
+
+Hint: What trait must our error type have for `main()` to return the return
+type that it returns?
+
+Another hint: It's not necessary to implement any methods inside the missing
+trait. (Some methods have default implementations that are supplied by the
+trait.)
+
+Another hint: Consult the tests to determine which error variants (and which
+error message text) to produce for certain error conditions.
+
+Challenge: There is one test that is marked `#[ignore]`. Can you supply the
+missing code that will make it pass? You may want to consult the standard
+library documentation for a certain trait for more hints.
+"""