You wouldn't.
But keep in mind that there are multiple kinds of exceptions.
Some exceptions, indicate scenarios the caller could reasonably have avoided. This include things like argument bound or null checks. A caller absolutely could avoid these exceptions by doing its own checks. This can be split between checks that the caller really should have done, like not passing null to a function that cannot take null, vs those where baking the relevant knowledge into the caller would be undesirable (perhaps because future versions of the library expect to accept more values).
There are exceptions that in theory a caller could avoid, but in practice it is impractical, like an exception thrown by a parser of some complex format if the provided input isn't legal. The only good way to avoid such an exception is to have a non-throwing parser that you can check with, but you probably don't want to parse twice. An alternative interface for the parser might be able to totally avoid the exception, returning either succeeded (with result tree) or fail with error message, but that would be a design choice of the implementor, not the caller.
There can be exceptions that indicate a logic bug in the impleentation (things like throwing if some invariant the implementation is in charge of is violated), but more often this is assertions instead.
Lastly, you have exceptions that there is no possible way the caller could always avoid. IO exceptions are among these. While you can sometimes do existence, space, or permission checks or similar to reduce the probability of getting certain exceptions, something else could race your app between the check and performing IO, and make them happen anyway.
The primary target for contracts are exceptions that callers both could and should have avoided, and the exception/assertion case that is trying to verify the implementation is working as expected.
The other categories of exceptions are more or less totally out of scope.