Microsoft 404 on folder delta endpoint permanently fails email sync
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<MessageChannelWorkspaceEntity, 'id'>, workspaceId: string, ): Promise<void> { 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.
This commit is contained in:
-25
@@ -249,31 +249,6 @@ export class MessageImportExceptionHandlerService {
|
||||
messageChannel: Pick<MessageChannelWorkspaceEntity, 'id'>,
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user