The logic error prevention Rust has is purely done by the type system. E.g. when you read a file name this is a special kind of string (OsString), because some operating systems allow for combinations of bytes as filenames that are not valid unicode. Now if you want your regular Rust string, you have to do a conversion and that conversion will return a Result<String>, which means you either get an Ok<String> or an Error. If you don't handle that unpacking your program won't compile. Now you could just unwrap the result and live with a crash when there is an Error (and in some cases that would be totally valid), but you now know and have to decide how to handle it.
This for example would be something I didn't even know could be a problem and Rust made me handle it properly just be representing the thing in the type system. There are countless such things in the language.
Of couese if you go deeper, you have to represent your problems properly in the type system and there you can certainly introduce mistakes.