From 569dde9985fad75e542811fdee1eb0a3251b718d Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Thu, 11 Jun 2026 19:10:06 +0200 Subject: [PATCH] fix: preserve folder list when mailbox refetch hits concurrent-request limit --- lib/jmap/client.ts | 12 ++++++++++++ stores/email-store.ts | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/jmap/client.ts b/lib/jmap/client.ts index 219fa4ce..8aa1772c 100644 --- a/lib/jmap/client.ts +++ b/lib/jmap/client.ts @@ -967,6 +967,8 @@ export class JMAPClient implements IJMAPClient { return this.getMailboxes(); } + let fetchFailed = false; + for (const accountId of accountIds) { const account = this.accounts[accountId]; const isPrimary = accountId === this.accountId; @@ -1013,10 +1015,20 @@ export class JMAPClient implements IJMAPClient { allMailboxes.push(...mailboxes); } } catch (error) { + fetchFailed = true; console.error(`Failed to fetch mailboxes for account ${accountId}:`, error); } } + // If every account fetch failed (e.g. a transient maxConcurrentRequests + // limit during a burst of deletes) we have an empty list that is NOT a + // real "this account has no mailboxes" result. Throwing lets the caller's + // catch preserve the existing folder list instead of clobbering it with + // [] — which would leave the sidebar stuck on "Loading mailboxes...". + if (allMailboxes.length === 0 && fetchFailed) { + throw new Error('Failed to fetch mailboxes for all accounts'); + } + return allMailboxes; } catch (error) { console.error("Failed to fetch all mailboxes:", error); diff --git a/stores/email-store.ts b/stores/email-store.ts index ab746e70..2b381a83 100644 --- a/stores/email-store.ts +++ b/stores/email-store.ts @@ -646,6 +646,14 @@ export const useEmailStore = create((set, get) => ({ try { const mailboxes = await client.getAllMailboxes(); + // Guard against a transient fetch returning an empty list (e.g. a server + // concurrent-request limit hit during a burst of deletes). Replacing a + // populated folder list with [] leaves the sidebar stuck on "Loading + // mailboxes..." until the next successful refetch. Keep what we have. + if (mailboxes.length === 0 && !isInitialLoad) { + return; + } + // Auto-select inbox if no mailbox is selected or the current selection // doesn't exist in the fetched list (e.g. after an account switch) const currentSelectedMailbox = get().selectedMailbox;