You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Set up a workspace with a direct (Plaid) company card feed.
Get the feed into a state where the feed itself has an error recorded (a backend card-import call for the feed fails), but no individual card has a broken scrape result. This makes hasFeedErrors true while isFeedConnectionBroken is false.
Go to Workspace → Company Cards. The banner "Card feed connection is broken. Please log into your bank so we can establish the connection again." is shown, and card assignment is blocked.
Click log into your bank (or attempt to assign a card on that feed).
Complete the bank login in the Plaid window.
Expected Result:
The reconnect flow either completes and closes the RHP, or shows an actionable error explaining that the reconnect failed.
Actual Result:
The RHP shows a back chevron, the title "Assign card", and a spinner — forever. There is no error, no timeout, and no way forward. The only option is to back out and retry, which lands in the same place.
Root Cause:
Two different definitions of "broken connection" disagree, and the page has no error state to fall back on.
The entry gate is broad.useAssignCard.ts:74 sets isSelectedFeedConnectionBroken = shouldPromptBrokenConnection || hasFeedErrors, and routes to the broken-connection page at useAssignCard.ts:119. A feed-level error sets hasFeedErrors, so we enter BrokenCardFeedConnectionPage. The banner uses the same disjunction at getShouldShowBrokenConnectionError.ts:14.
The inner branch is narrow.useUpdateFeedBrokenConnection.ts:22 derives isFeedConnectionBroken from card-level scrape failures only — it is false in this state. So BankConnection/index.tsx:126-139 skips the updateBrokenConnection() + closeRHPFlow() branch and instead takes the healthy-feed path, setting currentStep to ASSIGNEE or CONFIRMATION.
The host page cannot render that step.BrokenCardFeedConnectionPage.tsx:43-62 handles only BANK_CONNECTION and PLAID_CONNECTION. Every other step falls through to default: <LoadingPage title={translate('workspace.companyCards.assignCard')} /> — which is exactly the "Assign card" + spinner screen users report.
The same dead end was already fixed on the sibling page.RefreshCardFeedConnectionPage got both an isRefreshing guard in BankConnection (see the comment at BankConnection/index.tsx:132-133: "RefreshCardFeedConnectionPage can't render it and the modal would spin forever") and a NotFoundPage guard at RefreshCardFeedConnectionPage.tsx:70-72. BrokenCardFeedConnectionPage was left unguarded and still has neither.
Second path to the same spinner. If the feed's expiration is stale, BankConnection/index.tsx:141-143 returns early and waits for expiration to advance — which requires the card-import call to succeed, which is the thing that is failing. That renders the bare ActivityIndicator at BankConnection/index.tsx:219-224, also under an "Assign card" header. Both paths are closed by the same change.
Nothing surfaces the underlying failure either.useImportPlaidAccounts.ts:21-26 silently no-ops on an empty account list, and Plaid.ts:64-101 has no successData and no client-side timeout on plaidData.isLoading.
Proposed Direction:
Give BrokenCardFeedConnectionPage the same NotFoundPage guard its sibling has, so an unrenderable step is never silently swallowed by a spinner.
Stop BankConnection from setting a currentStep the host page cannot render when it was entered from the broken-connection route — mirror the existing isRefreshing guard.
Surface an error state when the card-import call fails, instead of leaving plaidData.isLoading set indefinitely.
Platforms:
Windows: Chrome
MacOS: Chrome / Safari
Notes:
Production logs confirm the server side of the reconnect returns jsonCode 200 and a valid Plaid link token; the client then makes no further API calls and simply spins. The stall is entirely client-side.
The trigger in the observed cases is a backend card-import failure that writes a feed-level error. That backend bug is tracked separately and is being worked on internally — this issue is only about the App never showing an error and spinning forever, which is a bug regardless of what caused the underlying failure.
Action Performed:
hasFeedErrorstrue whileisFeedConnectionBrokenis false.Expected Result:
The reconnect flow either completes and closes the RHP, or shows an actionable error explaining that the reconnect failed.
Actual Result:
The RHP shows a back chevron, the title "Assign card", and a spinner — forever. There is no error, no timeout, and no way forward. The only option is to back out and retry, which lands in the same place.
Root Cause:
Two different definitions of "broken connection" disagree, and the page has no error state to fall back on.
The entry gate is broad.
useAssignCard.ts:74setsisSelectedFeedConnectionBroken = shouldPromptBrokenConnection || hasFeedErrors, and routes to the broken-connection page atuseAssignCard.ts:119. A feed-level error setshasFeedErrors, so we enterBrokenCardFeedConnectionPage. The banner uses the same disjunction atgetShouldShowBrokenConnectionError.ts:14.The inner branch is narrow.
useUpdateFeedBrokenConnection.ts:22derivesisFeedConnectionBrokenfrom card-level scrape failures only — it is false in this state. SoBankConnection/index.tsx:126-139skips theupdateBrokenConnection()+closeRHPFlow()branch and instead takes the healthy-feed path, settingcurrentSteptoASSIGNEEorCONFIRMATION.The host page cannot render that step.
BrokenCardFeedConnectionPage.tsx:43-62handles onlyBANK_CONNECTIONandPLAID_CONNECTION. Every other step falls through todefault: <LoadingPage title={translate('workspace.companyCards.assignCard')} />— which is exactly the "Assign card" + spinner screen users report.The same dead end was already fixed on the sibling page.
RefreshCardFeedConnectionPagegot both anisRefreshingguard inBankConnection(see the comment atBankConnection/index.tsx:132-133: "RefreshCardFeedConnectionPage can't render it and the modal would spin forever") and aNotFoundPageguard atRefreshCardFeedConnectionPage.tsx:70-72.BrokenCardFeedConnectionPagewas left unguarded and still has neither.Second path to the same spinner. If the feed's
expirationis stale,BankConnection/index.tsx:141-143returns early and waits forexpirationto advance — which requires the card-import call to succeed, which is the thing that is failing. That renders the bareActivityIndicatoratBankConnection/index.tsx:219-224, also under an "Assign card" header. Both paths are closed by the same change.Nothing surfaces the underlying failure either.
useImportPlaidAccounts.ts:21-26silently no-ops on an empty account list, andPlaid.ts:64-101has nosuccessDataand no client-side timeout onplaidData.isLoading.Proposed Direction:
BrokenCardFeedConnectionPagethe sameNotFoundPageguard its sibling has, so an unrenderable step is never silently swallowed by a spinner.BankConnectionfrom setting acurrentStepthe host page cannot render when it was entered from the broken-connection route — mirror the existingisRefreshingguard.plaidData.isLoadingset indefinitely.Platforms:
Notes:
Filed from an internal support escalation; full log evidence lives in the linked internal issue.
Issue Owner
Current Issue Owner: @jmusial