Retrofit 2 — How to Detect Network and Conversion Errors in onFailure

A lot of professionally made apps use a bug tracking service, which collects errors and crashes of all users and lets us, as the developers, further improve the app by fixing the issues. The default Retrofit request callbacks offer an onFailure() method, which throws a variety of possible errors in one bucket.

In this tutorial, you'll learn how you can separate those errors and what our recommendation in dealing with them is.

Retrofit Series Overview

Tracking Retrofit's onFailure()

In the majority of our tutorials, we oversimplify the onFailure() callback and assume it's only called on network failures. As an example, let's look at one of our Retrofit call snippets:

call.enqueue(new Callback<List<GitHubRepo>>() {  
    @Override
    public void onResponse(Call<List<GitHubRepo>> call, Response<List<GitHubRepo>> response) {
        if (response.isSuccessful()) {
            Toast.makeText(ErrorHandlingActivity.this, "server returned data", Toast.LENGTH_SHORT).show();
            // todo display the data instead of just a toast
        }
        else {
            Toast.makeText(ErrorHandlingActivity.this, "Server returned an error", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onFailure(Call<List<GitHubRepo>> call, Throwable t) {
        Toast.makeText(ErrorHandlingActivity.this, "network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
    }
});

In our experience developers handle the onFailure() the same way: they just show a toast indicating an Internet connection issue, like the code above does, or use a similar UI hint. Additionally, many developers don't actually log the failure with a bug tracking service, like hockeyapp or instabug.

This is understandable, because 98% of the thrown errors in onFailure() will actually be Internet connection issues. When the user doesn't have an Internet connection and the request fails because of that, there is nothing we as the developer can do. It's not really necessary to track them.

Converter Errors

Unfortunately, one nasty cause for bugs can be missed this way: converter errors. When the converter (Gson, SimpleXML, …) fails due to some mismatch of the response payload and Java models, it'll also be thrown to the onFailure() callback.

When developing apps with Retrofit, a significant part of the time is fine-tuning the Java models to perfectly fit the API responses. Of course, during development everything works well. But once the app is out in production across thousands of users, the chances of some very rare mapping error occurring are increased significantly. Only if you're tracking the thrown onFailure callbacks, you'll be notified of this and are able to fix the bug.

Additionally, you also have a nice additional and cost-free layer of making sure changes to the API are not breaking the apps of existing users.

Distinguishing Error Causes

At this point, we've hopefully persuaded you to log onFailure() callbacks, at least the ones that were caused by a converter, to the central bug tracking service of your choice. But how can you distinguish between network errors and converter errors?

The onFailure() callback gives you as the second parameter the actual error object. You can simply check if the cause of the error was part of the Internet connection issue family (all part of IOException), or not:

@Override
public void onFailure(Call<List<BrokenGitHubRepo>> call, Throwable t) {  
    if (t instanceof IOException) {
        Toast.makeText(ErrorHandlingActivity.this, "this is an actual network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
        // logging probably not necessary
    }
    else {
        Toast.makeText(ErrorHandlingActivity.this, "conversion issue! big problems :(", Toast.LENGTH_SHORT).show();
        // todo log to some central bug tracking service
    }
}

In the callback above we've provoked a conversion error with changing from GitHubRepo to the BrokenGitHubRepo model. When the user has an Internet connection, Retrofit will throw the converter exception to the onFailure() callback. Because it's not an IOException, you can safely log it to your bug tracking service.

This way you're aware of rare, but still possible conversion issues, and are not getting thousands of connection issue reports. We prefer this approach of error logging in the onFailure() method.

Summary

In this tutorial you've learned why tracking onFailure() errors can be very beneficial. In particular, we've shown you how you can distinguish between regular Internet connection issues and fatal conversion errors.

Do you have further questions on this topic or about Retrofit in general? Just let us know on Twitter @futurestud_io or leave a comment below.

Enjoy coding & make it rock!

Explore the Library

Find interesting tutorials and solutions for your problems.