Skip to content

Commit 0554f0d

Browse files
authored
fix(functions): use notifyError() instead of throwing (#6773)
Throwing inside the `PublisherStream` causes a Runtime exception that can't be caught in the call site. Instead, we should use `notifyError()` so that the error can be caught in the `Subscriber#onError()` function. I tried to catch the exception using both of the code snippets below, but none of them worked. (they both work with the changes in this PR): ```kotlin functions.getHttpsCallable("nonExistentFunction") .stream().asFlow() .catch { // Handle error for a 404 function } .collect { // ... } ``` ```kotlin try { functions.getHttpsCallable("nonExistentFunction") .stream().asFlow() .collect { // ... } } catch(e: Exception) { // Handle error for a 404 function } ``` Runtime exception thrown: ``` FATAL EXCEPTION: OkHttp Dispatcher Process: com.google.samples.quickstart.functions, PID: 13321 com.google.firebase.functions.FirebaseFunctionsException: Value <html><head> of type java.lang.String cannot be converted to JSONObject Unexpected Response: <html><head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>404 Page not found</title> </head> <body text=#000000 bgcolor=#ffffff> <h1>Error: Page not found</h1> <h2>The requested URL was not found on this server.</h2> <h2></h2> </body></html> at com.google.firebase.functions.PublisherStream.validateResponse(PublisherStream.kt:316) at com.google.firebase.functions.PublisherStream.access$validateResponse(PublisherStream.kt:41) at com.google.firebase.functions.PublisherStream$startStreaming$1$4.onResponse(PublisherStream.kt:161) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:651) at java.lang.Thread.run(Thread.java:1119) ```
1 parent 1aca899 commit 0554f0d

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

firebase-functions/src/androidTest/java/com/google/firebase/functions/StreamTests.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,26 @@ class StreamTests {
143143
assertThat(subscriber.throwable).isInstanceOf(FirebaseFunctionsException::class.java)
144144
}
145145

146+
@Test
147+
fun nonExistentFunction_receivesError() = runBlocking {
148+
val function =
149+
functions.getHttpsCallable("nonexistentFunction").withTimeout(2000, TimeUnit.MILLISECONDS)
150+
val subscriber = StreamSubscriber()
151+
152+
function.stream().subscribe(subscriber)
153+
154+
withTimeout(2000) {
155+
while (subscriber.throwable == null) {
156+
delay(100)
157+
}
158+
}
159+
160+
assertThat(subscriber.throwable).isNotNull()
161+
assertThat(subscriber.throwable).isInstanceOf(FirebaseFunctionsException::class.java)
162+
assertThat((subscriber.throwable as FirebaseFunctionsException).code)
163+
.isEqualTo(FirebaseFunctionsException.Code.NOT_FOUND)
164+
}
165+
146166
@Test
147167
fun genStreamWeather_receivesWeatherForecasts() = runBlocking {
148168
val inputData = listOf(mapOf("name" to "Toronto"), mapOf("name" to "London"))

firebase-functions/src/main/java/com/google/firebase/functions/PublisherStream.kt

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,12 @@ internal class PublisherStream(
300300
val errorMessage: String
301301
if (response.code() == 404 && response.header("Content-Type") == htmlContentType) {
302302
errorMessage = """URL not found. Raw response: ${response.body()?.string()}""".trimMargin()
303-
throw FirebaseFunctionsException(
304-
errorMessage,
305-
FirebaseFunctionsException.Code.fromHttpStatus(response.code()),
306-
null
303+
notifyError(
304+
FirebaseFunctionsException(
305+
errorMessage,
306+
FirebaseFunctionsException.Code.fromHttpStatus(response.code()),
307+
null
308+
)
307309
)
308310
}
309311

@@ -313,16 +315,17 @@ internal class PublisherStream(
313315
val json = JSONObject(text)
314316
error = serializer.decode(json.opt("error"))
315317
} catch (e: Throwable) {
316-
throw FirebaseFunctionsException(
317-
"${e.message} Unexpected Response:\n$text ",
318-
FirebaseFunctionsException.Code.INTERNAL,
319-
e
318+
notifyError(
319+
FirebaseFunctionsException(
320+
"${e.message} Unexpected Response:\n$text ",
321+
FirebaseFunctionsException.Code.INTERNAL,
322+
e
323+
)
320324
)
325+
return
321326
}
322-
throw FirebaseFunctionsException(
323-
error.toString(),
324-
FirebaseFunctionsException.Code.INTERNAL,
325-
error
327+
notifyError(
328+
FirebaseFunctionsException(error.toString(), FirebaseFunctionsException.Code.INTERNAL, error)
326329
)
327330
}
328331
}

0 commit comments

Comments
 (0)