17

How come HttpURLConnection.getResponseCode() throws IOException even if the status is known?

Caused by: java.io.IOException: Server returned HTTP response code: 412 for URL: <my url>

It's not a problem of getting the response code because it is written in the exception message.

I would expect to have an option to get the status code (even if it's not ~200) without getting an exception, so I'll be able to decide in my code what to do.

Full stack trace:

Caused by: java.io.IOException: Server returned HTTP response code: 412 for URL: <my url>
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
... my code

UPDATE I changed the server side implementation to return a different status code (303), and it's working now (not throwing IOException). Meaning it is specifically related to 412.

danieln
  • 4,795
  • 10
  • 42
  • 64
  • Have you check what's maybe wrong with the server? http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error – Smutje Feb 24 '14 at 14:33
  • 1
    What do you mean? The server is working properly and returning 412 as expected. I want to be able to get the status code from the connection without it throwing exception. – danieln Feb 24 '14 at 14:34
  • 1
    I can't answer the why, but consider using a more sophisticated HTTP client. – Sotirios Delimanolis Feb 24 '14 at 14:37
  • 2
    Can you show the full stacktrace? – axtavt Feb 24 '14 at 14:39
  • Perhaps you could have clarified your question more regarding that you expected the server to behave like that and want to be able to obtain the status code, but you receive an exception on connection before being able to check for the status. – Smutje Feb 24 '14 at 14:40
  • @SotiriosDelimanolis, I can't. working as a Java Agent. – danieln Feb 24 '14 at 14:42
  • 1
    @Smutje how could it be if the status code is part of the exception message, meaning the connection was able to get the status code. – danieln Feb 24 '14 at 14:45
  • Which Java version are you using? I am not able to reproduce your problem and getResponseCode() should indeed return 412 instead of throwing an exception if that is what the server is actually returning. Try connecting to http://media.jarnbjo.de/412.php and check if you see the same problem with that URL. – jarnbjo Feb 24 '14 at 15:09
  • The implementation itself is pretty long and there are a lot of conditionals. Can you also show us how you make the HTTP request with your `HttpURLConnection`? – Sotirios Delimanolis Feb 24 '14 at 15:55
  • Can you show us your source code (around conn.getResponseCode)? – hgoebl Feb 24 '14 at 18:48

3 Answers3

8

I encountered the same problem today at work — our code was calling HttpURLConnection.getResponseCode() and ending up with Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: ... — and after some quality time diving through the JDK source code, I ended up figuring out the following:

  • getResponseCode() isn't actually throwing an exception!
  • An exception gets thrown from deep inside getResponseCode(), but it gets caught.
    • Before it's caught, some fields get set inside HttpURLConnection that allow getResponseCode() to succeed, which it does.
    • Also before it's caught, the exception gets saved to a field in a subclass of HttpURLConnection (specifically: sun.net.www.protocol.http.HttpURLConnection.rememberedException).
  • Subsequently, our code called getInputStream() directly, which is supposed to throw an exception in this case. (You're supposed to call getErrorStream() instead.)
  • getInputStream() throws an exception that wraps the original thrown-and-caught exception.
  • So we ended up getting a stacktrace with Caused by-s that referred to our line of code where we were calling getResponseCode(), even though our actual issue was later, in our line of code where we were calling getInputStream() directly.
    • The stacktrace also mentions that later line of code, but I didn't notice that at first.

I'm betting that your case was the same.

ruakh
  • 175,680
  • 26
  • 273
  • 307
7

ATTENTION: this may depend on the JVM version you are running!!! as tests of @SotiriosDelimanolis gave different results

The answer is in the source code of the HttpURLConnection and is related to all the errors that have error code > 400

If error code is equal 404 or 410 a FileNotFoundException is thrown else an IOException as

    if (respCode >= 400) {
        if (respCode == 404 || respCode == 410) {
            throw new FileNotFoundException(url.toString());
        } else {
            throw new java.io.IOException("Server returned HTTP" +
              " response code: " + respCode + " for URL: " +
              url.toString());
        }
    }

sun.net.www.protocol.http.HttpURLConnection Source code at line 1625:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection

My test on http://media.jarnbjo.de/412.php using :

Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

on Windows 64 bit

enter image description here

Community
  • 1
  • 1
0

What these other responses seem to miss, is that -- at least on my JDK -- what happens is that getResponseCode() does NOT throw exception but it sure looks like it DOES.

What actually happened to me -- I invoked getResponseCode() (which did not throw the exception) and then I invoked connection.getInputStream()

connection.getInputStream() does throw an exception -- which it should (by spec) -- BUT IT ADDS the exception stack trace for where you called getResponseCode() as the 'cause' -- i.e. if you look at the stack trace it looks something like this:

...
    ... 20 common frames omitted
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: http://localhost:8080/system
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1924)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1520)
    at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
    at yourpackage.yourcode.**YourClass.yourMethod**([line number where you invoked getResponseCode()]
    ... 22 common frames omitted

So, like I said, getResponseCode() does not throw exception, but SURE LOOKS like it does. Beware.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Sergey O.
  • 101
  • 4