Avoid rescuing StandardError

Problems ๐Ÿ”—

Rescuing from StandardError causes important issues to not bubble up.

There are 300+ errors that inherit from StandardError in Rails.

By rescuing StandardError all these errors will be caught, meaning we donโ€™t get good feedback in production so to whatโ€™s wrong.

This also causes problems when writing failing tests. The code under test will fail silently. Engineers then waste time figuring out why the test failed.

Bad ๐Ÿ”—

def perform!
  Rails.error.handle(
    StandardError,                                       # Rescue a generic exception
    fallback: -> { Failure.new("Something went wrong") } # Return a generic error
  )
    # ... perform work ...
  end
end
class BigMarkerAPIClient
  def all
    Rails.error.handle(
      StandardError,                                       # Rescue a generic exception
      fallback: -> { Failure.new("Something went wrong") } # Return a generic error
    )
      # ... API request ...
    end
  end
end
class BigMarkerAPIClient
  def all
    # ... API request ...
  rescue StandardError
    Sentry.capture_message("Something went wrong") 
  end
end

Good ๐Ÿ”—

def perform!
  Rails.error.handle(
    TooManyRequests,                                  # Rescue a specific exception
    fallback: -> { Failure.new(TooManyRequests.new) } # Return a specific error
  ) do
    # ... perform work ...
  end
end
class Lead
  def charge
    # ... sometimes the lead has expired ...
  rescue LeadExpired => error
    Rails.error.report(error, severity: :error) # Sends the error to both Datadog and Sentry
  end
end

Or let the code blow up and catch at a higher level:

class Lead
  def charge! # Note the bang
    # ... sometimes the lead has expired ...
  end
end

Edge Cases ๐Ÿ”—

There are a handful of cases where rescuing StandardError is appropriate.

One example - when youโ€™re creating a utility method such as a logger where it must not halt execution of the app.

In these cases, mark the exception as an error in Sentry so we get notified:

Rails.error.handle(StandardError, severity: :error) do