From 970d8511e192d7c6f10fc897d88729ecfaab68d0 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Wed, 4 Mar 2026 01:25:20 +0000 Subject: [PATCH] Microsoft 404 on folder delta endpoint permanently fails email sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://sonarly.com/issue/8521?type=bug When Microsoft Graph API returns HTTP 404 during message list fetch (e.g., deleted folder), the exception handler permanently marks the message channel as FAILED_UNKNOWN instead of retrying, breaking email sync for the affected user. Fix: ## Fix The `handleNotFoundException` method was permanently failing the message channel (`FAILED_UNKNOWN`) when a `NOT_FOUND` exception occurred during `MESSAGE_LIST_FETCH`. This was incorrect because Microsoft Graph API legitimately returns HTTP 404 for its folder delta endpoint when a mail folder is deleted, moved, or otherwise inaccessible — which the Microsoft driver maps to `MessageImportDriverExceptionCode.NOT_FOUND`. The fix removes the special-case branch that treated `NOT_FOUND` during `MESSAGE_LIST_FETCH` as an impossible/fatal state, and instead routes all `NOT_FOUND` exceptions (regardless of sync step) to the retry path: `resetAndMarkAsMessagesListFetchPending`. This is consistent with: - How `SYNC_CURSOR_ERROR` is handled (also resets and retries) - The original intent before the Oct 2025 refactor (commit `cd4800eb86d`) introduced the permanent failure path ```typescript file=packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts lines=247-256 private async handleNotFoundException( syncStep: MessageImportSyncStep, messageChannel: Pick, workspaceId: string, ): Promise { await this.messageChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending( [messageChannel.id], workspaceId, ); } ``` The old code for `MESSAGE_LIST_FETCH` (which created a "should never happen" Sentry error and called `markAsFailed`) is entirely removed. When the delta link becomes invalid (folder deleted/moved), the sync cursor resets and the channel queues for a fresh list fetch rather than being permanently broken. --- ...saging-import-exception-handler.service.ts | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts index dc3fa1e16f9..211d1902a89 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts @@ -249,31 +249,6 @@ export class MessageImportExceptionHandlerService { messageChannel: Pick, workspaceId: string, ): Promise { - if (syncStep === MessageImportSyncStep.MESSAGE_LIST_FETCH) { - await this.messageChannelSyncStatusService.markAsFailed( - [messageChannel.id], - workspaceId, - MessageChannelSyncStatus.FAILED_UNKNOWN, - ); - - this.exceptionHandlerService.captureExceptions( - [ - new Error( - 'Not Found exception occurred while fetching message list, which should never happen', - ), - ], - { - additionalData: { - messageChannelId: messageChannel.id, - syncStep, - }, - workspace: { id: workspaceId }, - }, - ); - - return; - } - await this.messageChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending( [messageChannel.id], workspaceId,