A rescue clause must not catch every exception only to swallow it.
A blanket rescue _ -> or rescue error -> that neither reraises, raises, nor
logs converts every crash — typos, match errors, genuine bugs — into a silent
wrong value. Rescue the specific exceptions you can handle, and let everything
else crash.
# BAD — swallows every exception, bugs included
def read_file(path) do
File.read!(path)
rescue
_ -> :error
end
# GOOD — rescues only the exception it can handle
def read_file(path) do
File.read!(path)
rescue
error in File.Error -> {:error, error}
endA blanket rescue is allowed when its body handles the exception it caught — reraising, raising a wrapping exception, or logging it:
# GOOD — logs before returning an error value
def read_file(path) do
File.read!(path)
rescue
error ->
Logger.error("#{__MODULE__}: read failed, error: #{inspect(error)}")
{:error, error}
endBoth the explicit try do ... rescue block and the implicit def ... rescue
form are checked.
What counts as handling is configurable through :allowed_recovery_calls.
Calls are matched by name, so a Logger renamed through an alias is not
recognised.