Skip to content

Commit 3a63f98

Browse files
markushiclaude
andcommitted
fix(sentry-okhttp): Skip synthetic 504 for FORCE_CACHE cache misses
OkHttp's CacheInterceptor synthesizes a 504 "Unsatisfiable Request" response when a request with `only-if-cached` (e.g. CacheControl.FORCE_CACHE) misses the cache. This is not a real server error, so don't capture it as a failed request event. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 740e4bf commit 3a63f98

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- Stop reporting OkHttp's synthetic 504 "Unsatisfiable Request" responses as errors for `CacheControl.FORCE_CACHE` (or any `only-if-cached`) cache misses ([#5276](https://github.com/getsentry/sentry-java/issues/5276))
8+
39
## 8.39.1
410

511
### Fixes

sentry-okhttp/src/main/java/io/sentry/okhttp/SentryOkHttpInterceptor.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public open class SentryOkHttpInterceptor(
5858
private val failedRequestTargets: List<String> = listOf(DEFAULT_PROPAGATION_TARGETS),
5959
) : Interceptor {
6060
private companion object {
61+
private const val HTTP_GATEWAY_TIMEOUT = 504
62+
6163
init {
6264
SentryIntegrationPackageStorage.getInstance()
6365
.addPackage("maven:io.sentry:sentry-okhttp", BuildConfig.VERSION_NAME)
@@ -386,6 +388,13 @@ public open class SentryOkHttpInterceptor(
386388
return false
387389
}
388390

391+
// A 504 on an only-if-cached (e.g. CacheControl.FORCE_CACHE) request is a synthetic
392+
// cache-miss response generated by OkHttp's CacheInterceptor, not a real server error,
393+
// so don't report it. See https://square.github.io/okhttp/recipes/#response-caching-kt-java
394+
if (response.code == HTTP_GATEWAY_TIMEOUT && request.cacheControl.onlyIfCached) {
395+
return false
396+
}
397+
389398
return true
390399
}
391400

sentry-okhttp/src/test/java/io/sentry/okhttp/SentryOkHttpInterceptorTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import kotlin.test.assertNotNull
3131
import kotlin.test.assertNull
3232
import kotlin.test.assertTrue
3333
import kotlin.test.fail
34+
import okhttp3.CacheControl
3435
import okhttp3.EventListener
3536
import okhttp3.Interceptor
3637
import okhttp3.MediaType.Companion.toMediaType
@@ -541,6 +542,30 @@ class SentryOkHttpInterceptorTest {
541542
)
542543
}
543544

545+
@Test
546+
fun `does not capture a synthetic 504 from OkHttp for a FORCE_CACHE cache miss`() {
547+
// No cache is configured on the client, so FORCE_CACHE is guaranteed to miss and
548+
// OkHttp's CacheInterceptor will synthesize a 504 "Unsatisfiable Request" response.
549+
val sut = fixture.getSut(captureFailedRequests = true)
550+
val request =
551+
Request.Builder()
552+
.url(fixture.server.url("/hello"))
553+
.cacheControl(CacheControl.FORCE_CACHE)
554+
.build()
555+
val response = sut.newCall(request).execute()
556+
557+
assertEquals(504, response.code)
558+
verify(fixture.scopes, never()).captureEvent(any(), any<Hint>())
559+
}
560+
561+
@Test
562+
fun `captures a real 504 when onlyIfCached is not set`() {
563+
val sut = fixture.getSut(captureFailedRequests = true, httpStatusCode = 504)
564+
sut.newCall(getRequest()).execute()
565+
566+
verify(fixture.scopes).captureEvent(any(), any<Hint>())
567+
}
568+
544569
@SuppressWarnings("SwallowedException")
545570
@Test
546571
fun `does not capture an error even if it throws`() {

0 commit comments

Comments
 (0)