So it means the client of your library can simply pattern-match on the result returned by cause() to find out if it was caused by, say, FileNotFoundException? Nice.
Nope, cause() returns an &Error, there's nothing you can pattern match there. And despite the documentation's claim, as far as I can see Error does not extend Any, which would be necessary for dynamic typechecking.
Also remember that cause() is recursive, you may need to traverse the whole chain before finding what you're looking for (not that you can find it at the moment)
I don't think that cause() being recursive is an issue, but I'm not sure why you'd want the cause if you can't do anything useful like attempt to downcast it.
You don't need to use cause(). For the LibError example, I think you'd instead want to pattern match against the actual variants defined in the enum, one of which is IoError(io::IoError), at which point you could match the IoError's kind against FileNotFound. This way you're depending on the published contract of the libraries in question, rather than the fact that you'll be given an error whose eventual cause is some file somewhere not being found, which is more of an implementation detail.
That's a good idea in general, but there are times where you do need downcasting. Maybe your generic DB framework can throw a specific error on MySQL that you known how to recover from, but which is only available from cause() but not from the library's contract.