CJCrafter/ChatGPT-Java-API

Allow user to capture error message from OpenAI API if rate limit exceed

Closed this issue · 2 comments

Thank you for this library. I have this one little issue.

When rate limit is exceeded, following error message is shown in logcat. I want to catch this error message and show it to end user.

com.google.gson.JsonSyntaxException: java.io.EOFException: End of input at line 1 column 2 path $.
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:59)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:102)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:70)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: java.io.EOFException: End of input at line 1 column 2 path $.
                           W  	at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1457)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:503)
                           W  	at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:422)
                           W  	at com.google.gson.internal.bind.TypeAdapters$28.read(TypeAdapters.java:779)
                           W  	at com.google.gson.internal.bind.TypeAdapters$28.read(TypeAdapters.java:725)
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:49)
                           W  	... 10 more
System.out                 I      "error": {
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 13 path $
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:76)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 13 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1465)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:551)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:71)
                           W  	... 8 more
System.out                 I          "message": "Rate limit reached for default-gpt-3.5-turbo in organization on requests per min. Limit: 3 / min. Please try again in 20s. Contact us through our help center at help.openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method.",
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 19 path $
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:76)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 19 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1465)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:551)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:71)
                           W  	... 8 more
System.out                 I          "type": "requests",
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 16 path $
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:76)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 16 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1465)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:551)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:71)
                           W  	... 8 more
System.out                 I          "param": null,
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:76)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1465)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:551)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:71)
                           W  	... 8 more
System.out                 I          "code": "rate_limit_exceeded"
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 16 path $
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:76)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 16 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1465)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:551)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:71)
                           W  	... 8 more
System.out                 I      }
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 5 path $
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:61)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:102)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:70)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 5 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:599)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:47)
                           W  	... 10 more
System.out                 I  }
System.err                 W  com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 1 path $
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:61)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:102)
                           W  	at com.google.gson.JsonParser.parseReader(JsonParser.java:70)
                           W  	at com.google.gson.JsonParser.parseString(JsonParser.java:51)
                           W  	at com.cjcrafter.openai.OpenAICallback.handleStream(OpenAICallback.kt:66)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:30)
                           W  	at com.cjcrafter.openai.OpenAICallback.onResponse(OpenAICallback.kt:25)
                           W  	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                           W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                           W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                           W  	at java.lang.Thread.run(Thread.java:1012)
                           W  Caused by: com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 1 path $
                           W  	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1659)
                           W  	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:599)
                           W  	at com.google.gson.stream.JsonReader.peek(JsonReader.java:433)
                           W  	at com.google.gson.internal.Streams.parse(Streams.java:47)
                           W  	... 10 more

try out the new release, which throws IO exceptions.

If you are still encountering issues, please send the json response you receive. I don't have any good way to test this right now, so if you encounter an issue, be sure to send me the exact text you receive from the api.

Can confirm the new release provides a much more user friendly error message. For example, from running the StreamChatCompletion.kt example:

Exception in thread "main" java.io.IOException: Unexpected code Response{protocol=h2, code=429, message=, url=https://api.openai.com/v1/chat/completions}
	at com.cjcrafter.openai.OpenAIImpl$streamResponses$1.iterator(OpenAIImpl.kt:100)
	at chat.StreamChatCompletionKt.main(StreamChatCompletion.kt:36)
	at chat.StreamChatCompletionKt.main(StreamChatCompletion.kt)

Though this still doesn't really allow the user to "capture" the response, it's at least clear in the logs.

Might be good to define a custom exception type?

data class HttpResponseException(
    override val message: String,
    val url: String,
    val statusCode: Int,
) : IOException(message) {

    internal constructor(response: Response) : this(response.message, response.url.toString, response.statusCode)
}