Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code e5c592ccf6 Missing object metadata for new messageChannelMessageAssociationMessageFolder in un-migrated workspaces
https://sonarly.com/issue/3881?type=bug

The v1.19.0 release introduced the `messageChannelMessageAssociationMessageFolder` standard object and code that unconditionally uses it during message import, but workspaces that haven't run the 1.19 upgrade migration command lack this object metadata, causing message import to fail.

Fix: Added a guard in both `MessagingMessageFolderAssociationService` and `MessagingDeleteFolderMessagesService` to check if the `messageChannelMessageAssociationMessageFolder` object exists in the workspace's metadata before attempting to get its repository.

The check uses `getWorkspaceContext().objectIdByNameSingular` (already populated by `executeInWorkspaceContext`) to verify the object is present. If not (workspace hasn't run the 1.19 upgrade migration), the code gracefully skips the folder association operations instead of throwing a `MALFORMED_METADATA` error.

This is the correct fix because:
1. The `messageChannelMessageAssociationMessageFolder` object is new in v1.19.0 and requires a per-workspace backfill migration
2. The message import worker runs immediately after deployment, before all workspaces are migrated
3. Skipping is safe — un-migrated workspaces have no folder associations to read/write, and will get full functionality once the upgrade command runs
2026-03-13 10:46:04 +00:00
2 changed files with 24 additions and 0 deletions
@@ -4,6 +4,7 @@ import { isDefined } from 'twenty-shared/utils';
import { In } from 'typeorm';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { getWorkspaceContext } from 'src/engine/twenty-orm/storage/orm-workspace-context.storage';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
import { type MessageChannelMessageAssociationMessageFolderWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association-message-folder.workspace-entity';
import { type MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
@@ -38,6 +39,17 @@ export class MessagingDeleteFolderMessagesService {
let totalDeletedCount = 0;
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(async () => {
const workspaceContext = getWorkspaceContext();
// Skip if workspace hasn't been migrated to include this object yet
if (
!workspaceContext.objectIdByNameSingular[
'messageChannelMessageAssociationMessageFolder'
]
) {
return;
}
const messageFolderAssociationRepository =
await this.globalWorkspaceOrmManager.getRepository<MessageChannelMessageAssociationMessageFolderWorkspaceEntity>(
workspaceId,
@@ -4,6 +4,7 @@ import { In } from 'typeorm';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { getWorkspaceContext } from 'src/engine/twenty-orm/storage/orm-workspace-context.storage';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
import { type MessageChannelMessageAssociationMessageFolderWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association-message-folder.workspace-entity';
@@ -30,6 +31,17 @@ export class MessagingMessageFolderAssociationService {
const authContext = buildSystemAuthContext(workspaceId);
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(async () => {
const workspaceContext = getWorkspaceContext();
// Skip if workspace hasn't been migrated to include this object yet
if (
!workspaceContext.objectIdByNameSingular[
'messageChannelMessageAssociationMessageFolder'
]
) {
return;
}
const repository =
await this.globalWorkspaceOrmManager.getRepository<MessageChannelMessageAssociationMessageFolderWorkspaceEntity>(
workspaceId,