Search code examples
rustlanguage-lawyerprogram-entry-pointexit-code

In Rust, what happens if main function returns Err?


According to The Rust Reference,

If a main function is present, (snip), and its return type must be one of the following:

  • ()

  • Result<(), E> where E: Error

but it doesn't say what happens when main() returns (), Ok(()) or Err(<value>).

As far as I tested,

() Ok(()) Err(<value>)
Exit Status 0 0 1
Additional Behavior - - Error: <value> is printed to stderr

Are these behaviors defined, explicitly explained or guaranteed in some documentation? In particular, can I assume

  • a program always exits with 1 status when main() returns Err(<value>)?

  • the error message displayed when main() returns Err(<value>) is always of the form Error: <value>?


Notes:

  • I want some sort of documented guarantee rather than an empirical explanation. This is why I added #language-lawyer tag.

  • This question is not about When should I use () and when should I use Result<(), E>? or such. One can find answers (or at least hints or criteria) to such questions in many documentations or tutorials, as you know.


Updates:

Termination trait is finally stabilized in Rust 1.61.0 (source).


Solution

  • The behavior of different return values from main is defined by the std::process::Termination trait:

    trait std::process::Termination

    A trait for implementing arbitrary return types in the main function.

    This trait is documented to return libc::EXIT_SUCCESS on success and libc::EXIT_FAILURE on error.

    The default implementations are returning libc::EXIT_SUCCESS to indicate a successful execution. In case of a failure, libc::EXIT_FAILURE is returned.

    But those values aren't guaranteed to be 0 and 1 on non-POSIX systems.


    As for printing the error message, Termination requires E: Debug and does print the Debug impl to stderr, but I don't believe it's guaranteed to stay exactly the same.

    impl<E: fmt::Debug> Termination for Result<!, E> {
        fn report(self) -> ExitCode {
            let Err(err) = self;
            eprintln!("Error: {:?}", err);
            ExitCode::FAILURE.report()
        }
    }
    

    Source