#236 Jul 2, 2026

236. Result::flatten — Collapse a Result<Result<T, E>, E> in One Call

Ended up with a Result<Result<T, E>, E> and reached for a nested match to peel it? When both layers share the same error type, Result::flatten (stable since 1.89) does it in one call.

How you get a doubly-wrapped Result

It usually sneaks in when you map a fallible operation over something that’s already a Result:

1
2
3
4
5
6
7
8
fn first_word(line: Result<&str, String>) -> Result<Result<u32, String>, String> {
    line.map(|s| {
        s.split_whitespace()
            .next()
            .ok_or_else(|| "empty line".to_string())
            .and_then(|w| w.parse::<u32>().map_err(|e| e.to_string()))
    })
}

The outer Result is “did we have a line?”, the inner one is “did it parse?”. Same String error on both — but the type is now Result<Result<u32, String>, String>, which no caller wants to touch.

The manual peel

1
2
3
4
5
6
7
8
let nested: Result<Result<u32, String>, String> = Ok(Ok(42));

let flat: Result<u32, String> = match nested {
    Ok(inner) => inner,   // inner is itself a Result
    Err(e) => Err(e),
};

assert_eq!(flat, Ok(42));

Correct, but it’s boilerplate that hides the intent.

flatten does exactly this

1
2
3
4
5
6
7
let ok:    Result<Result<u32, String>, String> = Ok(Ok(42));
let inner: Result<Result<u32, String>, String> = Ok(Err("bad".into()));
let outer: Result<Result<u32, String>, String> = Err("io".into());

assert_eq!(ok.flatten(),    Ok(42));
assert_eq!(inner.flatten(), Err("bad".to_string()));
assert_eq!(outer.flatten(), Err("io".to_string()));

Ok(Ok(x)) becomes Ok(x); either Err — inner or outer — passes straight through. Option has the same method, Option::flatten, for Option<Option<T>>.

The catch: error types must match

flatten is Result<Result<T, E>, E>Result<T, E> — one E. If the two layers carry different error types, flatten can’t merge them. Reach for and_then instead, which lets ?-style conversion do the work:

1
2
3
4
5
let nested: Result<Result<u32, String>, String> = Ok(Ok(7));

// same as .flatten() here, but and_then can also adapt the inner error
let flat = nested.and_then(|inner| inner);
assert_eq!(flat, Ok(7));

When the errors already line up, flatten is the clearest way to say “unwrap one layer of nesting.”

← Previous 235. Iterator::rposition — Find the Last Match Without Reversing-and-Subtracting