Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Retrofit POST java.io.IOException: unexpected end of stream on Connection caused by java.io.EOFException: \n not found:

Ask Question

I have went through all the question related to this and yet, I haven't found a solution that works for me.

Im using retrofit 2.8.1 and OkHttp 4.5.0 .

My service interface looks like the following

public interface MlApiService
    @POST
    @Multipart
    Call<List<PreprocessedDocument>> postDocument( @Url String apiUrl, @Part MultipartBody.Part document,
    @Part ( "document_id") RequestBody documentId );

And I build the client like the following with requestTimeoutInSeconds set to 90 seconds.

public void init()
    GsonBuilder gson = new GsonBuilder();
    gson.registerTypeAdapter( new TypeToken<List<PreprocessedDocument>>() {}.getType(), new CustomResponseDeserializer() );
    HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
    logInterceptor.setLevel( HttpLoggingInterceptor.Level.HEADERS );
    OkHttpClient client = new OkHttpClient.Builder().retryOnConnectionFailure( true ).addInterceptor( logInterceptor )
        .readTimeout( requestTimeoutInSeconds, TimeUnit.SECONDS ).build();
    //Dummy Base URL must be provided. otherwise client won't get initialized
    Retrofit retrofit = new Retrofit.Builder().baseUrl( "http://thisIsJustDummyUrlForTheSakeOfAddingBaseUrl.com/" )
        .client( client ).addConverterFactory( GsonConverterFactory.create( gson.setLenient().create() ) ).build();
    mlApiService = retrofit.create( MlApiService.class );

The request reaches the server and just when the server responds I get the following error:

Caused by: java.io.IOException: unexpected end of stream on Connection{34.XXX.XXX.9:8085, proxy=DIRECT hostAddress=/34.XXX.XXX.9:8085 cipherSuite=none protocol=http/1.1}
    at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)
    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
Caused by: java.io.EOFException: \n not found: limit=0 content=…
    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:227)
    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:211)
    at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:187)

Few things which I have tried so far

  • retryOnConnectionFailure(true)
  • .addHeader("Connection","close")
  • .header("Accept-Encoding", "identity")
  • The API works fine from postman but it fails when I try from code. So I tried the same headers sent by postman. Still no luck.

    Few observations:

  • It sometimes works. Doesn't fail always.(The same file works always with postman)
  • It always works for other files(never an issue).
  • The request reaches the server and process the request without any errors and responds too. I get the error immediately after server completes processing and responds back to client.
  • EDIT 1: The server I hit is backed by gunicorn/20.0.4 and uses Flask. I don't have access to the server code. And I doubt that the response sent received has some garbage characters causing the error. I don't know how to log the raw response before being read by retrofit/okhttp.

    EDIT 2:

    I ran the Curl command with verbose and this is what I got.

    < HTTP/1.1 100 Continue

  • Empty reply from server
  • Connection #0 to host xx.xxx.xxx.9 left intact curl: (52) Empty reply from server
  • If it is consistently working on Postman, your best option is to compare the request with all headers and body with the request you generate with your client. You could also look into the file content does it have any special or Unicode character as you mention it is specifically for this file that you are getting this error. Is there a dos2unix type situation applicable ? – somshivam Apr 25, 2020 at 7:53 @somshivam see observation#3. Also, if we see the stacktrace at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203) It says readResponseHeaders. Does this leave a clue? error whille reading the response headers? – Arun Gowda Apr 25, 2020 at 8:54

    Short story

    The problem was with the server I was hitting. It was not sending any response (literally nothing. No headers, no body, nothing).

    Long story

    So after going through all the related answers on stackoverflow, other good websites and trying out so many solution which I have mentioned in the question itself, it did not solve my issue.

    After carefully reading the stack trace, I came across the following line.

    okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)
    

    The client (my code) is trying to read the Response header and that's when the error java.io.EOFException: \n not found: limit=0 content= is thrown.

    This gave me a hint that the problem could be with the server and not with the client. So I thought I should try with a different client and see if I can see the raw response.

    The first tool that came to my mind was Curl (Postman used to give the generic Could not get any response and this did not happen consistently). I hit the server using curl with verbose option and boom! I got the following response:

    curl -v --location --request POST 'http://XX.XXX.XXX.9:8085/psc/document_upload' --form 'document=@/home/user376/Downloads/test-1.pdf' --form 'document_id=22004494_ae7f_4998_a1d8_73249bda9905'
    Note: Unnecessary use of -X or --request, POST is already inferred.
    *   Trying XX.XXX.XXX.9...
    * Connected to XX.XXX.XXX.9 (XX.XXX.XXX.9) port 8085 (#0)
    > POST /psc/document_upload HTTP/1.1
    > Host: XX.XXX.XXX.9:8085
    > User-Agent: curl/7.49.0
    > Accept: */*
    > Content-Length: 4684053
    > Expect: 100-continue
    > Content-Type: multipart/form-data; boundary=------------------------a8446c7eedb10689
    < HTTP/1.1 100 Continue
    * Empty reply from server
    * Connection #0 to host XX.XXX.XXX.9 left intact
    curl: (52) Empty reply from server
    

    And that confirmed the problem was with the server and not with the client(Retrofit / http).

    Moral of the story: Sometimes you have to read the stacktrace word by word even if it doesn't seem worth looking in to :)

    You get a empty reply without a status-line. This is the problem. HTTP-requests normally return a status line (e.g. HTTP/1.1 200 OK\r\n), which contains the status code see https://www.ietf.org/rfc/rfc2616.txt chapter 6.1. This is normally a server error.

    Most probably there are 2 things, happening at the same time.
    First, the url contains a port which is not commonly used AND secondly, you are using a VPN or proxy that does not support that port.
    Personally, I had the same problem.
    My server port was 45860 and I was using pSiphon anti-filter VPN.
    In that condition my Postman reported "connection hang-up" only when server's relpy was an error with status codes bigger than 0. (it was fine when some text was returning from server with no error code)
    Then I changed my web service port to 8080 on my server and, WOW, it worked! although psiphon vpn was connected.
    Therefore, my suggestion is that if you can change the server port, so try it, or check if there is a proxy problem. Perhaps your Postman and acual app are not on the same machin.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.