No public retry-policy hook exists in Paging 3
Direct answer: in Paging 3.x there is no documented public API to inject a custom retry policy into PagingSource, and PagingConfig exposes no retry, backoff, or max-attempts fields. One correction to the premise: Paging 3 does not automatically retry failed loads. When load() returns LoadResult.Error, the matching LoadState becomes Error and stays there until something calls LoadState.retry(), typically the UI. So the non-configurable automatic retry described in the question is not documented library behavior; what exists is a manual retry entry point, not a policy.
What the public API actually exposes
PagingSource constructor: key and value type parameters only, no retry handler, attempt count, or backoff parameter.
PagingConfig: pagination tuning such as pageSize, prefetchDistance, enablePlaceholders, initialKey, maxSize, and jumpThreshold, nothing retry-related.
LoadState.retry(): a user-initiated reload after an error, not an automatic policy hook.
Where custom retry logic belongs
Because the library will not run your policy, you own it in one of two places:
- Inside
PagingSource.load(): wrap the fetch in your own retry loop and return LoadResult.Error only after attempts are exhausted:
override suspend fun load(params: LoadParams<Key>): LoadResult<Key, Value> {
var attempt = 0
while (true) {
try {
val page = fetchPage(params) // Room DAO call or Exposed query
return LoadResult.Page(data = page, prevKey = null, nextKey = null)
} catch (e: Exception) {
attempt++
if (attempt >= maxAttempts) return LoadResult.Error(e)
delay(backoffMillis(attempt)) // your policy: exponential + jitter
}
}
}
- In the data layer: for Exposed, wrap the query in
retryTransaction { ... } so transient failures are retried before the result reaches Paging; for Room, wrap the suspend DAO call in the same kind of loop. PagingSource then only sees terminal failures.
Caveats and verification
- A retry loop inside
load() runs on Paging's load worker; long backoffs delay LoadState updates and can interact with placeholder behavior, so keep maxAttempts small and add jitter.
- Version assumption: this describes the Paging 3.x (3.0 and later) public API surface. Verify against your exact artifact version; autocomplete on
PagingConfig( and the PagingSource constructor should show no retry parameters.
- Behavior check: write a unit test whose
load() returns LoadResult.Error and collect load states from the Pager; you will observe LoadState.Error with no automatic re-emission unless retry() is called.
One diagnostic detail that would change the recommendation: are you observing automatic retries in your LoadState stream, which would point to a wrapper or another layer doing the retrying, or only manual retry() calls from the UI? If the former, the retry policy already lives somewhere in your own code; find it there rather than in Paging.