# std::io::ErrorKind::NotFound error message: add filename

**URL:** <https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941>\
**Category:** libs\
**Created:** [May 19, 2025, 1:47pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941 "2025-05-19T13:47:15Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![KonradHoeffner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/konradhoeffner/32/12871_2.png) [@KonradHoeffner](https://internals.rust-lang.org/u/KonradHoeffner)\
**Post date:** [May 19, 2025, 1:47pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/1 "2025-05-19T13:47:15Z")

</div>

When you open a file that does not exist you get an appropriate NotFound error kind, however the message "No such file or directory" is missing the name of the file or directory that is missing. If your program is loading a lot of files it would be very helpful for the user to see which one of them is missing. Sure, one can always customize the error message and in a final product we should not unwrap() in such a case, but why not make the default user experience as best as possible?

```rust
fn main() {
    std::fs::File::open("doesnotexist.txt").unwrap();
}

```

```rust
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }

```

I propose to improve it as such:

```rust
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "File or directory 'doesnotexist.txt' not found" }

```

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 19, 2025, 2:04pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/2 "2025-05-19T14:04:22Z")

</div>

> but why not make the default user experience as best as possible?

Because that would incur an allocation cost to carry the path, which has to be owned by the error message. `io::Error` is a slim representation of operating system errors, and those do not contain the path that failed. So if you want it to be userfriendly you have to enrich the error with some context, as various crates offer.

In other words, it's possible to add the data. But if it where there by default then everyone would pay the cost because it can't be removed.

Some kinds of filesystem access patterns encounter more error cases than success cases (e.g. probing a bunch of paths until a file is found), so making errors more expensive would affect them greatly.

See [Include the errored file path (when available) in std::io::Error instances · Issue #2885 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/issues/2885) for some prior discussion.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 19, 2025, 2:10pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/3 "2025-05-19T14:10:46Z")

</div>

_(Slightly duplicate answer, I started writing this before @the8472 posted their reply 😉)_

One problem here could be overhead in error handling:

The `std::io::Error` type currently uses a compact representation (only 1 pointer large), which ensures it's cheap to pass around, but it _also_ aids in minimizing the need for incurring any overhead in terms of allocations, in many common cases. For many functions, like `File::open`, this means the raw OS error code that the `std::io::Error` is created from is simply [slightly bit-shifted and tagged](https://doc.rust-lang.org/1.87.0/src/std/io/error/repr_bitpacked.rs.html#175-190), but [otherwise left untouched](https://doc.rust-lang.org/1.87.0/src/std/io/error.rs.html#637-644). If the error message was supposed to mention the file name, with a type like `std::io::Error: 'static`, there would first need to be a new allocation created in order to remember this file name as part of the error.

---

<div class="post-metadata">

**Author:** ![KonradHoeffner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/konradhoeffner/32/12871_2.png) [@KonradHoeffner](https://internals.rust-lang.org/u/KonradHoeffner)\
**Post date:** [May 19, 2025, 3:22pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/4 "2025-05-19T15:22:02Z")

</div>

Thank you for the GitHub link, I read through it and it was really interesting! It mentions [crates.io: Rust Package Registry](https://crates.io/crates/fs-err) which I may use as a drop in for std::fs to get clearer error messages.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [May 20, 2025, 3:43am UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/5 "2025-05-20T03:43:17Z")

</div>

> [@steffahn](#):
>
> with a type like `std::io::Error: 'static`

In the case of `std::fs::File::open("doesnotexist.txt")` the error type could share a lifetime with the argument though. Admittedly this would make it more difficult to just bubble it up the call stack.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [May 20, 2025, 4:20am UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/6 "2025-05-20T04:20:49Z")

</div>

You'd have to `.map_err()` at lots of call sites to convert to an owned version, which makes it not that much easier to use than using `.map_err()` at each such site to add the path in either owned or borrowed form. Less error-prone, though (no chance of adding the _wrong_ path).

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [May 20, 2025, 5:48pm UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/7 "2025-05-20T17:48:26Z")

</div>

I think in the vast majority of cases, the overhead of an allocation on error unimportant. It's a tiny optimization that most users won't notice, but it has very visible downsides that users are annoyed by.

(the size of the `io::Error` type is important since it shows up on every `write`, but `open` is relatively rare, and could afford using a slow path to build `io::Error`).

BTW, `File::open` already allocates a NUL-terminated and/or UTF-16 version of the path on the happy path. If you want the error to be super efficient, the implementation internals could recycle that allocation.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 21, 2025, 10:41am UTC](https://internals.rust-lang.org/t/std-notfound-error-message-add-filename/22941/8 "2025-05-21T10:41:25Z")

</div>

> [@kornel](#):
>
> BTW, `File::open` already allocates a NUL-terminated and/or UTF-16 version of the path on the happy path

It uses a stackbuffer up to a limit (currently 384 bytes).
