Remove workflows fallback on 4xx errors#3562
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3562 +/- ##
==========================================
+ Coverage 80.19% 80.23% +0.04%
==========================================
Files 371 371
Lines 15239 15252 +13
Branches 2112 2114 +2
==========================================
+ Hits 12221 12238 +17
+ Misses 2168 2163 -5
- Partials 850 851 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6258755 to
8283944
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8283944. Configure here.
| onErrorHandler(e.toPurchasesError().also { errorLog(it) }) | ||
| onErrorHandler( | ||
| e.toPurchasesError().also { errorLog(it) }, | ||
| GetWorkflowsErrorHandlingBehavior.SHOULD_FALLBACK_TO_CACHED_WORKFLOWS, |
There was a problem hiding this comment.
On iOS I've generalized instead of duplicating the whole logic. But it's fine. We can always follow-up after releasing.
| // A 4xx means the server intentionally changed/removed these workflows. Don't | ||
| // resurrect a stale list from disk; just settle the callbacks so offerings | ||
| // delivery isn't stranded. Caches are left as they are (no restore, no purge). | ||
| completePendingCallbacks(appUserID) |
There was a problem hiding this comment.
nit: 4xx leaves the timestamp stale, so we re-hit the backend every call while still serving the stale in-memory map. Before this PR the restore path re-stamped it, so we used to back off.
Want to keep retrying every call, or stamp it so a sticky 4xx backs off? Offerings does the same thing so either way is fine, just flagging.
There was a problem hiding this comment.
let's mimic what offerings does
There was a problem hiding this comment.
there was actually a divergence with offerings here. In offerings we call forceCacheStale on 4xx errors
…ehavior A force-refresh returning SHOULD_NOT_FALLBACK left the in-memory timestamp untouched, so a still-fresh list would suppress retries until TTL expired. Calling invalidateWorkflowsListTimestamp() mirrors OfferingsManager calling forceCacheStale() on the same error class. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Summary
If the workflows list fetch fails, we restore the cache from disk on any error, including 4xx. So a 404 (workflow removed) or 403 (misconfigured key) made the SDK resurrect the previous list from disk and keep serving it.
This PR mirrors what we do for offerings policy. It does not require any backend change.
Fallback behavior (identical to offerings):
The disk copy is left untouched on 4xx (no purge).
Doing the same for the workflow detail endpoint will be done in a future PR.
Note
Medium Risk
Changes offerings-gated workflows list caching on network errors; behavior is aligned with offerings and heavily tested but affects paywall/offering mapping when the API returns 4xx.
Overview
Workflows list fetch failures now follow the same fallback rules as offerings, instead of always restoring from disk on any error.
Backend.getWorkflowsreports aGetWorkflowsErrorHandlingBehaviorwith each error: transport failures, 5xx, and malformed success bodies still signal fallback to cached workflows; HTTP 4xx signalsSHOULD_NOT_FALLBACK.WorkflowManageruses that signal on list errors—on 4xx it does not read the workflows list or detail envelopes from disk, invalidates the in-memory list freshness so the next call retries, and still completes pendingonCompletecallbacks so offerings delivery is not blocked. Fallback-eligible errors keep the existing disk restore path, now inrestoreWorkflowsListFromDisk. Tests cover the new behavior mapping and the 4xx manager path.Reviewed by Cursor Bugbot for commit 99321ba. Bugbot is set up for automated code reviews on this repo. Configure here.