Okhttp: java.lang.IllegalStateException: closed when trying to access response in onResponse(Response response)

Created on 26 Dec 2014  Â·  29Comments  Â·  Source: square/okhttp

I get

java.lang.IllegalStateException: closed
            at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:455)
            at okio.Buffer.writeAll(Buffer.java:594)
            at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:87)
            at com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:56)
            at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:82)

when trying to access the response body using:

response.body().string();

inside onResponse(Response response) callback.

Most helpful comment

Are you reading the response body 2x? You can only call string() once.

All 29 comments

Are you reading the response body 2x? You can only call string() once.

That was probably the case.

You can only call string() once. true

You can call string() once. But I don't know why

Because response body can be huge so OkHttp doesn’t store it in memory, it reads it as a stream from network when you need it.

When you read body as a string() OkHttp downloads response body and returns it to you without keeping reference to the string, it can’t be downloaded twice without new request.

On Tue, Jul 19, 2016 at 5:46 PM fattolium

<
mailto:fattolium [email protected]

wrote:

You can call string() once. But I don't know why

—

You are receiving this because you are subscribed to this thread.

Reply to this email directly,
https://github.com/square/okhttp/issues/1240#issuecomment-233655904
, or
https://github.com/notifications/unsubscribe-auth/AA7B3EORk4IpQyujb1gMCpIcFpT2uJkWks5qXOMogaJpZM4DMQVK
.

https://github.com/square/okhttp/issues/1240#issuecomment-233655904

once requst once download

response.body.string should be defined as a variable.but in fact ,i also don't why this.

Pffft. At least give people the option to do that if they want! Exceptions don't help much.

@artem-zinnatullin thanks very much!

Beware if you have response.body().string() in your watch list that will cause your code to fail. Since watch list will run automatically.

Thanks a lot....solved a huge problem for me 👍

if you have used response.body().string() once then you can new one same response and return in case that you will use "response.body().string()" again. It won't throw any exception if you do this.

At least it would be nice to add explanation to javadocs about this.
I just broke my production because of twice call to string()

Which Javadocs did you read? That’s where we should add such a note.

It's documented on ResponseBody.

On Wed, Sep 13, 2017 at 11:04 AM Włodzimierz Rożkow <
[email protected]> wrote:

At least it would be nice to add explanation to javadocs about this.
I just broke my production because of twice call to string()

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/square/okhttp/issues/1240#issuecomment-329197139, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAEEEZm2BB9oiE_q1GHhuSJ8E3vD_JiRks5sh-72gaJpZM4DMQVK
.

I've read javadocs for string() method in ResponseBody:

  /**
   * Returns the response as a string decoded with the charset of the
   * Content-Type header. If that header is either absent or lacks a charset,
   * this will attempt to decode the response body as UTF-8.
   */

Maybe my version is a bit outdated? 2.7.5

Try the following:

ResponseBody responseBodyCopy = response.peekBody(Long.MAX_VALUE);
responseBodyCopy.string();

it works for me

@KaNcHeR It looks like a dirty hack, but it works :D Thanks a lot

Don't try to use response.body.string() directly. Just using like below:
ResponseBody responseBody = response.body();
String content = responseBody.string();
// Do something with "content" variable

Reason:
The the string of body is stored in memory to variable content, so we don't need to care of whether the state is closed.

Check own okhttp interceptor's, throuble may be inside.

       @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) {
            if (response.isSuccessful()) {

                try {

                    final String url = response.request().url().toString();
                    Log.i(TAG, " url: " + url);

                    Thread diffThread = new Thread(new Runnable() {
                    @Override
                     public void run() {

                            try {

                                System.setProperty("http.keepAlive", "false");

                                ResponseBody responseBody = response.body();

                                if (responseBody == null) {
                                    return;
                                }

                                String source = responseBody.string();
                                } catch(Exception e){
                                  ---> Exception! message:closed
                                }
  }

How can I do that? It gives an error if it is in a different thread ?

Response body is not stored in memory. .string() reads as stream from network. That is it.

Try storing response in string variable separately like this,

String res = response.body().string();

Then use variable res.

how come. it is not working

For me the problem was the wrapper function that returned Responseobject. Like this

callAPI(...){
.....
client.newCall(request).execute().also { 
        return it
    }
...

I tried something like this

Response response = chain.proceed(newRequest);
Response responseTmp = chain.proceed(newRequest);

responseTmp.body().string();

and it works

That makes two HTTP requests. You don't want to do that.

Adding this bit as it may help someone else. I was puzzled to encounter the very same exception while calling ResponseBody.string() only once.

The problem, I realized later, was due to the execution context of my request: using a try with resources block with the response causes the same problem when the response body is read outside of the try block:

try (Response response = client.newCall(request.build()).execute()) {
    return response;
} //response.close() called implicitly by the JVM

If response is processed outside this method, the IllegalStateException is equally thrown. That's because the try with resources block will call response.close(). An easy workaround for such a design is to read the body in the try block itself and return it (or both it and the response object in a different data structure)

just call response.close();

example :

@Override
public void onResponse(Call call, Response response) throws IOException {

                    final int code  = response.code();
                    final String body = response.body().string();
                    response.close();

                    Login.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                    //do any thing with body variable 
            Print(body);    
                        }
                    });

            }
Was this page helpful?
0 / 5 - 0 ratings