SDK-392 Fix Pending/Fulfill never resolving when auth retries exhausted - #1023
Merged
sumeruchat merged 1 commit intoApr 2, 2026
Merged
Conversation
When a 401 JWT error triggers auth token retry in RequestProcessorUtil, the result Fulfill is never resolved if retries are eventually exhausted. This causes upstream callers (e.g. the React Native SDK initialize callback) to hang indefinitely. Three changes: - AuthManager.requestNewAuthToken: invoke onSuccess(nil) when shouldPauseRetry is true so pending callback chains are notified - AuthManager.scheduleAuthTokenRefreshTimer: invoke successCallback(nil) when shouldSkipTokenRefresh is true instead of silently returning - RequestProcessorUtil.sendRequest: check token in the retry callback and reportFailure when nil instead of calling attemptSend again Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1023 +/- ##
==========================================
- Coverage 70.80% 70.73% -0.08%
==========================================
Files 112 112
Lines 9201 9215 +14
==========================================
+ Hits 6515 6518 +3
- Misses 2686 2697 +11 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
franco-zalamena-iterable
self-requested a review
April 2, 2026 10:11
franco-zalamena-iterable
approved these changes
Apr 2, 2026
franco-zalamena-iterable
left a comment
Contributor
There was a problem hiding this comment.
This is a good patch for the issue. But i think we should tackle this problem in a more substantial way in the future, i think the caller should not need to handle null cases, it should be something that is dealt internally.
sumeruchat
deleted the
fix/SDK-392-resolve-pending-on-auth-retry-exhaustion
branch
April 2, 2026 12:46
joaodordio
restored the
fix/SDK-392-resolve-pending-on-auth-retry-exhaustion
branch
April 2, 2026 14:46
joaodordio
deleted the
fix/SDK-392-resolve-pending-on-auth-retry-exhaustion
branch
April 2, 2026 15:18
2 tasks
joaodordio
restored the
fix/SDK-392-resolve-pending-on-auth-retry-exhaustion
branch
April 7, 2026 09:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes a bug where
RequestProcessorUtil.sendRequest()leaves itsresultFulfill permanently unresolved when a 401 JWT error triggers auth token retry and all retries are eventually exhausted. This causes any upstream caller chained on the Pending to hang indefinitely — including theIterableAPI.initialize2callback used by the React Native SDK.Reported by: CarGurus (SDK-392) —
Iterable.initialize()promise hangs on React Native New Architecture.Root Cause
When
sendRequest()receives a 401 JWT error, it schedules an auth token refresh viaAuthManager.scheduleAuthTokenRefreshTimerwith a callback that callsattemptSend()to retry the request. TheresultFulfill is only resolved insideattemptSend()on success or non-JWT error — it is never resolved in the 401-JWT branch itself.The retry chain eventually terminates when
AuthManager.requestNewAuthToken()detectsretryCount >= maxRetryand returns early at line 45 — but it does so without invoking theonSuccesscallback. This means:invokePendingCallbacksis never calledattemptSendcallback queued byRequestProcessorUtilis orphanedresultFulfill is never resolved (neither.resolve()nor.reject())Pendingchain upstream —fetcher.fetch()→inAppManager.start()→implementation.start()→initialize2callback — hangs foreverSimilarly,
scheduleAuthTokenRefreshTimersilently returns whenshouldSkipTokenRefreshis true (auth paused), dropping the callback without invoking it.Call chain (verified):
Changes
AuthManager.requestNewAuthToken: WhenshouldPauseRetryreturns true (retries exhausted or paused), invokeonSuccess?(nil)before returning so the caller chain is notified instead of silently abandoned.AuthManager.scheduleAuthTokenRefreshTimer: WhenshouldSkipTokenRefreshreturns true, invokesuccessCallback?(nil)before returning instead of dropping the callback.RequestProcessorUtil.sendRequest: Check the token in thescheduleAuthTokenRefreshTimercallback — ifnil(retries exhausted), callreportFailureto reject theresultFulfill instead of callingattemptSend()again.Regression Risk Analysis
Low risk
requestNewAuthTokenonly invokesonSuccess(nil)whenshouldPauseRetryis true — the happy path where a valid token is returned goes throughonAuthTokenReceived→invokePendingCallbacks(with: token)as before.RequestProcessorUtilonly callsreportFailurewhentokenis nil.reportFailureinRequestProcessorUtil.Medium risk — review carefully
shouldSkipTokenRefreshpath: WhenpauseAuthRetryis true and a non-scheduled refresh is requested, we now invoke the callback with nil. If any caller was scheduling a refresh while auth was paused and expecting it to simply be ignored (no callback), they will now receive a nil callback. Review callers ofscheduleAuthTokenRefreshTimerto confirm this is safe.scheduleAuthTokenRefreshTimercalled fromonAuthTokenReceived(nil)(line 204): When auth delegate returns nil,onAuthTokenReceivedschedules another refresh with the sameonSuccess. With this fix, if that refresh is skipped (e.g. retries paused),onSuccess(nil)is called, which propagates up toinvokePendingCallbacks(nil)→RequestProcessorUtilreports failure. Previously this would have silently stalled. Verify this matches expected behavior.Not affected
apply()method inRequestProcessorUtil(does not usescheduleAuthTokenRefreshTimer)Testing
How to test:
authDelegatethat always returns nil (simulating token retrieval failure)IterableAPI.initialize2(callback:)and verify the callback fires withfalseafter retries are exhausted (instead of hanging forever)trueEdge cases:
pauseAuthRetries(true)called during active retry cycle