Retrofit 2 RequestBody writeTo() method called twice

If you're using writeTo() to track file upload progress, you need to distinguish between the callers of writeTo(). Basically writeTo() can be called by any interceptor in the chain, e.g. any logging interceptor such as a HttpLoggingInterceptor/OkHttpProfilerInterceptor/StethoInterceptor, and this method provides no context for that.

The simplest approach (as pointed out by other answers) is to get rid of those interceptors that require access to the request body. But this may be not always feasible.

Another solution is to make use of the fact that a server call is performed by a CallServerInterceptor which is the last interceptor in the chain (according to the docs). You can inspect stack trace prior to further handling. Yes, this is ugly. But this way you don't have to modify your interceptors or leave room for subtle bugs when someone else comes up and adds another interceptor.

override fun writeTo(sink: BufferedSink) {
    val isCalledByCallServerInterceptor = Thread.currentThread().stackTrace.any { stackTraceElement ->
        stackTraceElement.className == CallServerInterceptor::class.java.canonicalName
    }

    // TODO
}

I figured out yet another case for twice called writeTo() method. I use OkHttpClient without Retrofit and HttpLoggingInterceptor, and I have the twice called problem.

Solution: the problem appears after upgrade Android Studio to 3.1.1 and enable Advanced Profiling in run project configuration. So disable Advanced Profiling.


Decreasing log level from BODY to HEADERS, BASIC or NONE solved this problem for me


The solution below might help you out , although it might be too late. :p

Remove HttpLoggingInterceptor Object in your Api Client which will not execute writeTo() function twice.Basically , HttpLoggingInterceptor loads the data buffer first ( for internal logging purpose ) by calling writeTo() and then again calls writeTo() for uploading the data to server.

  HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
  logging.setLevel(HttpLoggingInterceptor.Level.BODY);
  httpClient.addInterceptor(logging);