New request
#20699: [v2.6.1] Cursor-recovery edge case: PR #20664 fix doesn't apply when workspace cursor advanced past 2.3 from earlier failed upgrade attempt
We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.
TL;DR
PR #20664 / commit 6b3064e2 (included in v2.6.1) fixes the relationTargetFieldMetadataId upgrade bug for clean upgrade paths. It does NOT fix it for instances whose workspace cursor advanced past 2.3 during a previous failed upgrade attempt — the early 2.3 fast instance command only runs at the cursor-transition through 2.3, so workspaces left in a "phantom future" state (e.g., cursor stuck at 2.5.0/failed) never get the column created.
This issue is about that cursor-recovery edge case, which is distinct from the happy-path bug fixed in #20675/#20664.
Why this is a separate bug from #20675
Sonarly's RCA on this issue (see bot comment below) correctly identifies the underlying root cause and confirms 6b3064e2 fixes it. We verified gh api compare 6b3064e2...v2.6.1 returns behind_by: 0 — the fix is in v2.6.1.
The fix works by registering an early 2.3 fast instance command that creates core."viewFilter"."relationTargetFieldMetadataId" before any 2.3 workspace command runs. This works perfectly for:
- Fresh installs (no cursor)
- Upgrades from any version ≤ 2.3 (cursor crosses 2.3 transition → fix runs)
- pg_restore from clean source whose workspace cursor is at or before 2.3
It does not work for the path we hit, because our workspace cursor was already past 2.3 by the time we ran v2.6.1, and the early 2.3 command in instance-commands.constant.ts only triggers during the 2.3 cursor transition.
Our exact reproduction
-
pg_dumpfrom a Twenty self-hosted instance running thelatesttag pulled on 2026-05-08 (imagesha256:06dfce40f62d1f5b1aebe2d5a05cad0c629177ab456b70c8bf7b7df2f48f52ad, approximately v2.2.x). DB contents: 1 workspace, 1 user, 4 persons, 4 opportunities, 6 workflows, 11 workflowRuns, 17 MB total. -
Provision a new Ubuntu 24.04 ARM server. Deploy a fresh Twenty stack with
postgres:16-alpineand an emptydefaultdatabase. -
pg_restorethe dump on the new server. Schema state: 90 tables (62 core + 28 workspace_*), workspace cursor at the cluster's last-known position. -
First attempt: start
twentycrm/twenty:latest(pulled on 2026-05-18 around 10:24 UTC — that's between v2.4.0 and v2.5.x). The upgrade chain runs, advances workspace cursor through 2.3.x → 2.4.x, attempts2.5.0_NormalizeCompositeFieldDefaults, fails oncolumn ViewFilterEntity.relationTargetFieldMetadataId does not existduring workspace migration. UI is stuck on skeleton loaders. -
Workaround attempt: pin back to the older image to get a working UI again:
image: twentycrm/twenty@sha256:06dfce40f62d1f5b1aebe2d5a05cad0c629177ab456b70c8bf7b7df2f48f52adThe old image still reads the schema fine (its entity doesn't expect this column yet), UI works, data intact. BUT the workspace cursor is now stuck at
2.5.0 failedperupgrade:status. -
Switch to
twentycrm/twenty:v2.6.1(sha256:0f4ee43ad39224aceea37c1c7457c567764287d6fa5ad7424936c7fb39c463c1, released 2026-05-18 22:06 UTC, contains fix commit6b3064e2). -
Same error.
upgrade:statusoutput:Workspace Perezagruzka (8252e65c-cb39-4d9e-8996-ec403ff324e7) Inferred version: 2.5.0 Latest command: NormalizeCompositeFieldDefaults 1778000001000 (2.5.0) (workspace) Status: Failed Executed by: v2.6.1 Error: [QueryFailedError] column ViewFilterEntity.relationTargetFieldMetadataId does not existThe fix commit's early 2.3 instance command
2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filteris shipped in the binary, but the upgrade runner doesn't execute it because the workspace cursor is already past 2.3.
What actually unblocked the upgrade
Manually adding the missing column directly to the database, then restarting twenty-server and twenty-worker:
ALTER TABLE core."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid;
After this, the upgrade chain progressed past 2.5.0_NormalizeCompositeFieldDefaults, completed every subsequent command through 2.6.0, and upgrade:status now reports:
Instance: v2.6.0 Up to date
Workspace: Perezagruzka v2.6.0 Up to date
Summary: 1 up to date, 0 behind, 0 failed
UI works, all data (4 persons, 4 opportunities, 4 notes, 6 workflows, 11 workflowRuns) intact.
Why we think this should be fixed (or at least documented)
The "tried newer image, failed mid-chain, pinned back, then retried with proper version" pattern is realistic for self-hosters who don't read the changelog before pulling. Once you've been bitten by this state, no shipped Twenty release will recover the workspace without manual SQL — because the cursor-based runner correctly refuses to re-run commands it thinks have already passed.
Two reasonable fixes:
Option A (preferred): make the fix idempotent across cursor positions. The new early 2.3 fast instance command currently only fires when the runner is transitioning through the 2.3 cursor. Either:
- always run it on startup as a safety net (it's already idempotent via
IF NOT EXISTS), or - run it whenever any 2.3-2.5 cursor is encountered, not only on the 2.3 transition.
Option B: document the manual ALTER TABLE in v2.6.x release notes as the recovery procedure when upgrade:status shows a workspace failed at 2.5.0 NormalizeCompositeFieldDefaults after coming from a pre-2.3 schema. At minimum, add a check in WorkspaceFlatViewFilterMapCacheService.computeForCache() that returns an empty cache (instead of crashing) when the column is absent, paired with a one-time runtime check that triggers the missing 2.3 fast instance command.
Technical inputs
Environment:
- Image:
twentycrm/twenty:v2.6.1(sha256:0f4ee43ad39224aceea37c1c7457c567764287d6fa5ad7424936c7fb39c463c1) - Postgres:
postgres:16-alpine(16.13 on aarch64) - OS: Ubuntu 24.04 LTS arm64 (Netcup ARM 3000 VPS)
- Source instance: image
sha256:06dfce40f62d1f5b1aebe2d5a05cad0c629177ab456b70c8bf7b7df2f48f52ad(thelatesttag at 2026-05-08, approximately v2.2.x) - Workspace ID:
8252e65c-cb39-4d9e-8996-ec403ff324e7 - Inferred workspace version at time of failure: 2.5.0 (failed at
NormalizeCompositeFieldDefaults 1778000001000) - Number of TypeORM migrations in
core."_typeorm_migrations"after pg_restore: 182 (latest:AddIsInitialToUpgradeMigration1775909335324) - Number of TypeORM migration files in v2.6.1 image at
/app/packages/twenty-server/dist/database/typeorm/core/migrations/common/: 182 as well
Failing query (generated by WorkspaceFlatViewFilterMapCacheService.computeForCache):
SELECT "ViewFilterEntity"."workspaceId" AS "ViewFilterEntity_workspaceId",
"ViewFilterEntity"."universalIdentifier" AS "ViewFilterEntity_universalIdentifier",
"ViewFilterEntity"."applicationId" AS "ViewFilterEntity_applicationId",
"ViewFilterEntity"."id" AS "ViewFilterEntity_id",
"ViewFilterEntity"."fieldMetadataId" AS "ViewFilterEntity_fieldMetadataId",
"ViewFilterEntity"."operand" AS "ViewFilterEntity_operand",
"ViewFilterEntity"."value" AS "ViewFilterEntity_value",
"ViewFilterEntity"."viewFilterGroupId" AS "ViewFilterEntity_viewFilterGroupId",
"ViewFilterEntity"."positionInViewFilterGroup" AS "ViewFilterEntity_positionInViewFilterGroup",
"ViewFilterEntity"."subFieldName" AS "ViewFilterEntity_subFieldName",
"ViewFilterEntity"."relationTargetFieldMetadataId" AS "ViewFilterEntity_relationTargetFieldMetadataId",
"ViewFilterEntity"."viewId" AS "ViewFilterEntity_viewId",
"ViewFilterEntity"."createdAt" AS "ViewFilterEntity_createdAt",
"ViewFilterEntity"."updatedAt" AS "ViewFilterEntity_updatedAt",
"ViewFilterEntity"."deletedAt" AS "ViewFilterEntity_deletedAt"
FROM "core"."viewFilter" "ViewFilterEntity"
WHERE (("ViewFilterEntity"."workspaceId" = $1))
Verified fix presence in v2.6.1:
$ gh api repos/twentyhq/twenty/compare/6b3064e2bae39f41265104a648f5b0f73ff18eb4...v2.6.1 | jq '{status, ahead_by, behind_by}'
{
"status": "ahead",
"ahead_by": 18,
"behind_by": 0
}
Fix commit 6b3064e2 is contained in v2.6.1. The new early 2.3 fast instance command and the idempotent 2.6 command are both shipped. But they don't execute on our workspace because the cursor is already past 2.3.
Cross-references
- #20675 — original report of the same column error on a different repro path (clean 2.5.1 → 2.5.3 upgrade), fixed by #20664 / commit
6b3064e2. - #20666 — different startup loop bug on fresh self-host 2.4.0 installs (cursor and safety-check mismatch, not directly related but indicates the upgrade-cursor system has edge cases).
- PR #20664 (commit
6b3064e2) — the fix that this issue argues does not cover the cursor-recovery path.
The fix for missing relationTargetFieldMetadataId only executes during the 2.3 cursor transition, so workspaces already past that point remain broken.
- packages/twenty-server/src/database/typeorm/core/migrations/common
- packages/twenty-server/src/engine/workspace-manager/workspace-migration/commands
- packages/twenty-server/src/engine/workspace-manager/workspace-migration/instance-commands.constant.ts
- packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner.service.ts