From 6b3064e2bae39f41265104a648f5b0f73ff18eb4 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Mon, 18 May 2026 10:42:40 +0200 Subject: [PATCH] fix(server): add relationTargetFieldMetadataId column early in upgrade sequence (#20664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Cross-version upgrade fails at the 2.3 `DropMessageDirectionFieldCommand` stage: ``` [QueryFailedError] column ViewFilterEntity.relationTargetFieldMetadataId does not exist at WorkspaceFlatViewFilterMapCacheService.computeForCache ``` (see https://github.com/twentyhq/twenty-infra/actions/runs/25929264129/job/76219964380) Same shape as #20584 (subFieldName), one column over. ### Root cause 1. The 2.3 `DropMessageDirectionFieldCommand` builds a workspace migration that deletes a `fieldMetadata` (the `direction` field). 2. `WorkspaceMigrationRunnerService.run` walks the metadata cascade graph and pulls `viewFilter` into the dependency set because `viewFilter` is the inverse one-to-many of `fieldMetadata`. 3. That maps to cache keys → `flatViewFilterMaps` gets requested → `WorkspaceFlatViewFilterMapCacheService.computeForCache` runs. 4. `computeForCache` does `viewFilterRepository.find({ where: { workspaceId }, withDeleted: true })` with no `select`, so TypeORM emits a SELECT that includes `relationTargetFieldMetadataId` — column only added by the 2.6 fast instance command `1798000005000`, not yet run at the 2.3 stage. 💥 ### Why v2.5.0 / v2.5.1 passed They didn't include #20527 (one-hop relation filters, May 14), which added `relationTargetFieldMetadataId` to `ViewFilterEntity` and the 2.6 instance command. The CI base image (v1.22) seeded the DB, then the v2.5.0/v2.5.1 container ran upgrade commands against an entity that didn't yet know about this column. --- ...target-field-metadata-id-to-view-filter.ts | 21 +++++++++++++++++++ ...target-field-metadata-id-to-view-filter.ts | 4 ++-- .../instance-commands.constant.ts | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter.ts diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter.ts new file mode 100644 index 0000000000..6964c78c6a --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter.ts @@ -0,0 +1,21 @@ +import { QueryRunner } from 'typeorm'; + +import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; +import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; + +@RegisteredInstanceCommand('2.3.0', 1747234300000) +export class AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand + implements FastInstanceCommand +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`, + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000005000-add-relation-target-field-metadata-id-to-view-filter.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000005000-add-relation-target-field-metadata-id-to-view-filter.ts index 024295f988..913e14ed27 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000005000-add-relation-target-field-metadata-id-to-view-filter.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000005000-add-relation-target-field-metadata-id-to-view-filter.ts @@ -9,7 +9,7 @@ export class AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( - `ALTER TABLE "core"."viewFilter" ADD "relationTargetFieldMetadataId" uuid`, + `ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`, ); await queryRunner.query( `CREATE INDEX "IDX_VIEW_FILTER_RELATION_TARGET_FIELD_METADATA_ID" ON "core"."viewFilter" ("relationTargetFieldMetadataId") WHERE "relationTargetFieldMetadataId" IS NOT NULL`, @@ -27,7 +27,7 @@ export class AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand `DROP INDEX "core"."IDX_VIEW_FILTER_RELATION_TARGET_FIELD_METADATA_ID"`, ); await queryRunner.query( - `ALTER TABLE "core"."viewFilter" DROP COLUMN "relationTargetFieldMetadataId"`, + `ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`, ); } } diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts index 4c1a369d38..2d8d0aa81c 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts @@ -21,6 +21,7 @@ import { BackfillPageLayoutWidgetPositionSlowInstanceCommand } from 'src/databas import { AddCacheTokensToAgentChatThreadFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777455269302-add-cache-tokens-to-agent-chat-thread'; import { AddLogoToApplicationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777539664664-add-logo-to-application'; import { AddSubFieldNameToViewSortEarlyFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234200000-add-sub-field-name-to-view-sort'; +import { AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter'; import { AddUpgradeMigrationWorkspaceIdIndexFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777308014234-add-upgrade-migration-workspace-id-index'; import { AddDeletedAtToAgentChatThreadFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777682000000-add-deleted-at-to-agent-chat-thread'; import { ConnectionProviderSyncableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777896012579-connection-provider-syncable-entity'; @@ -61,6 +62,7 @@ export const INSTANCE_COMMANDS = [ AddPageLayoutIdToCommandMenuItemFastInstanceCommand, AddConditionalAvailabilityExpressionToPageLayoutWidgetFastInstanceCommand, AddSubFieldNameToViewSortEarlyFastInstanceCommand, + AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand, AddUpgradeMigrationWorkspaceIdIndexFastInstanceCommand, AddIsPreInstalledToApplicationRegistrationFastInstanceCommand, AddProviderExecutedToAgentMessagePartFastInstanceCommand,