Skip to content

fix(server): make workflow-core + person-avatar upgrade commands v2-safe - #24724

Merged
charlesBochet merged 2 commits into
mainfrom
charles/fix-orm-v2-upgrade-command-object-guards
Aug 25, 2026
Merged

fix(server): make workflow-core + person-avatar upgrade commands v2-safe#24724
charlesBochet merged 2 commits into
mainfrom
charles/fix-orm-v2-upgrade-command-object-guards

Conversation

@charlesBochet

@charlesBochet charlesBochet commented Aug 24, 2026

Copy link
Copy Markdown
Member

Context

#24692 removed IS_ORM_V2_READ_PATH_ENABLED and collapsed to the v2 path: GlobalWorkspaceOrmManager.getRepository now always routes to the v2 datasource, and WorkspaceORMEntityMetadatasCacheService.computeForCache returns [] unconditionally (the v1 GlobalWorkspaceDataSource metadata is no longer built).

Several workspace upgrade commands still relied on v1 behavior and break under this. It wasn't caught because the cross-version-upgrade smoke test only runs on release tags — cutting one off main surfaced it (staging-ci failed at BackfillWorkflowVersionToCore and then MigratePersonAvatarUrlToAvatarFile).

Two incompatibilities fixed

1. Missing-object guards only caught the v1 error type. Backfill/repair commands that skip when a workspace predates an object caught EntityMetadataNotFoundError (thrown by v1 getMetadata). The v2 datasource instead throws TwentyOrmV2Exception(UNKNOWN_OBJECT), so the guard missed it and the upgrade failed. Added a shared isWorkspaceObjectNotFoundError predicate covering both error types and used it in the four affected commands:

  • 2-20 backfill-workflow-version-to-core
  • 2-22 backfill-workflow-version-core-links
  • 2-23 backfill-workflow-core-links
  • 2-28 repair-orphan-core-workflow-versions

2. Reading through the iterator's raw v1 datasource. MigratePersonAvatarUrlToAvatarFile read persons via dataSource.getRepository('person'), where dataSource is the iterator's GlobalWorkspaceDataSource. Since computeForCache now returns [], that path throws EntityMetadataNotFoundError: No metadata for "person" even when the person object exists (it failed on the seed workspace). Routed the read through globalWorkspaceOrmManager.getRepository (v2) instead — the command already runs inside the iterator's executeInWorkspaceContext.

Validation

Validated on the v2.34.x release line: these exact fixes took staging-ci (build + cross-version-upgrade smoke test) from failing to green. This PR brings them to main.

Note: the 2-9 AI-model-preferences command also matches dataSource.getRepository but reads a core entity (KeyValuePairEntity) on the core datasource, so it's unaffected and left as-is.

Review in cubic

…de commands

With IS_ORM_V2_READ_PATH_ENABLED removed, getRepository routes to the v2 datasource,
which throws TwentyOrmV2Exception(UNKNOWN_OBJECT) — not EntityMetadataNotFoundError —
when a workspace upgrading from before an object existed lacks that object. The
workflow-core backfill/repair commands only caught the v1 error, so the cross-version
upgrade smoke test failed at BackfillWorkflowVersionToCore with 'Object workflowVersion
does not exist'. Add a shared isWorkspaceObjectNotFoundError guard covering both error
types and use it in the four affected upgrade commands.

(cherry picked from commit f4125df)
… v2 datasource

MigratePersonAvatarUrlToAvatarFile read persons via the iterator's raw v1
GlobalWorkspaceDataSource (dataSource.getRepository). With the flag removed,
computeForCache returns [] unconditionally, so that path's getMetadata throws
EntityMetadataNotFoundError even when the person object exists — failing the
cross-version upgrade on the seed workspace. Read through globalWorkspaceOrmManager
.getRepository (which routes to the v2 datasource) instead.

(cherry picked from commit b694880)
Copilot AI lite review requested due to automatic review settings August 24, 2026 22:32
@twenty-ci-bot-public

Copy link
Copy Markdown

🚀 Preview Environment Ready!

Your preview environment is available at: https://randy-social-republic-asp.trycloudflare.com

This environment will automatically shut down after 5 hours.

@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes workflow and person-avatar upgrade commands compatible with the v2 workspace ORM.

  • Adds a shared guard for both legacy and v2 missing-object errors.
  • Routes person avatar migration reads and writes through the workspace-scoped v2 ORM manager.
  • Applies the missing-object guard consistently across four workflow upgrade commands.

Confidence Score: 5/5

The PR appears safe to merge, with no actionable correctness or security failures identified.

The missing-object predicate is limited to the two expected ORM error representations, and the avatar command uses a correctly scoped, compatible v2 repository whose file updates satisfy the existing validation contract.

Important Files Changed

Filename Overview
packages/twenty-server/src/database/commands/upgrade-version-command/utils/is-workspace-object-not-found-error.util.ts Correctly normalizes the legacy TypeORM and v2 ORM missing-object errors used by upgrade commands.
packages/twenty-server/src/database/commands/upgrade-version-command/2-22/2-22-workspace-command-1783960128000-migrate-person-avatar-url-to-avatar-file.command.ts Moves person access to the workspace-scoped v2 repository while preserving compatible query, update, permission-bypass, and file-field behavior.
packages/twenty-server/src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783526282685-backfill-workflow-version-to-core.command.ts Extends the missing-workflowVersion skip path to the v2 ORM error without suppressing unrelated exception codes.
packages/twenty-server/src/database/commands/upgrade-version-command/2-22/2-22-workspace-command-1784193207000-backfill-workflow-version-core-links.command.ts Uses the shared missing-object predicate while retaining the existing backfill behavior.
packages/twenty-server/src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784286707000-backfill-workflow-core-links.command.ts Uses the shared missing-object predicate while retaining the existing workflow backfill behavior.
packages/twenty-server/src/database/commands/upgrade-version-command/2-28/2-28-workspace-command-1785600000000-repair-orphan-core-workflow-versions.command.ts Uses the shared missing-object predicate while retaining the existing orphan-repair behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Workspace upgrade command] --> B{Target object exists?}
  B -->|No: v1 or v2 missing-object error| C[Skip workspace safely]
  B -->|Yes| D[Acquire workspace repository]
  D --> E[Run workflow backfill or avatar migration]
  E --> F[Complete workspace upgrade]
Loading

Reviews (1): Last reviewed commit: "fix(server): route person-avatar backfil..." | Re-trigger Greptile

@twenty-ci-bot-public

Copy link
Copy Markdown

🟡 Standard review · 1 finding

Safe to merge — one non-blocking test gap

High-level — Clean DRY consolidation of a duplicated not-found predicate into a shared util, extended for the v2 datasource; no schema, migration, or public-surface change and well under the size limit.
Low-level — Line-by-line is clean (correct util suffix/boolean naming, valid WHY comment, isDefined usage); only the new util's v2 branch lacks a regression spec.

💬 1 inline comment on the diff.


Reviewed against the pr-review standard — high-level then low-level. Advisory; human review still required. Run details.

// The v1 GlobalWorkspaceDataSource throws EntityMetadataNotFoundError, while the v2
// datasource throws TwentyOrmV2Exception(UNKNOWN_OBJECT). Backfill commands must treat
// both as "object not provisioned yet" and skip rather than fail the upgrade.
export const isWorkspaceObjectNotFoundError = (error: unknown): boolean =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Nit · Low-level · Backend tests / regression test

New pure util with a branch has no unit spec, leaving the v2 UNKNOWN_OBJECT path untested

The whole point of the change — treating TwentyOrmV2Exception(UNKNOWN_OBJECT) as "object not provisioned" — is asserted nowhere; the pre-existing 2-28 spec only exercises the v1 EntityMetadataNotFoundError branch. Add an is-workspace-object-not-found-error.util.spec.ts covering both error types and a non-matching error.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make several workspace upgrade commands compatible with the post-#24692 world where ORM v2 is the only supported workspace entity read path, by (a) broadening “object missing” guards to recognize the ORM v2 error type and (b) routing one command’s workspace reads through GlobalWorkspaceOrmManager (v2) instead of the iterator’s v1 GlobalWorkspaceDataSource.

Changes:

  • Add isWorkspaceObjectNotFoundError to treat both v1 EntityMetadataNotFoundError and v2 TwentyOrmV2ExceptionCode.UNKNOWN_OBJECT as “object not provisioned”.
  • Update multiple workflow-related upgrade commands to use the shared predicate in their missing-object guards.
  • Update MigratePersonAvatarUrlToAvatarFile to read person via GlobalWorkspaceOrmManager.getRepository (v2).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/twenty-server/src/database/commands/upgrade-version-command/utils/is-workspace-object-not-found-error.util.ts Introduces shared predicate to classify “workspace object missing” across ORM v1/v2 error types.
packages/twenty-server/src/database/commands/upgrade-version-command/2-28/2-28-workspace-command-1785600000000-repair-orphan-core-workflow-versions.command.ts Switches the skip-guard to the shared predicate.
packages/twenty-server/src/database/commands/upgrade-version-command/2-23/2-23-workspace-command-1784286707000-backfill-workflow-core-links.command.ts Switches the skip-guard to the shared predicate.
packages/twenty-server/src/database/commands/upgrade-version-command/2-22/2-22-workspace-command-1784193207000-backfill-workflow-version-core-links.command.ts Switches the skip-guard to the shared predicate.
packages/twenty-server/src/database/commands/upgrade-version-command/2-22/2-22-workspace-command-1783960128000-migrate-person-avatar-url-to-avatar-file.command.ts Routes person reads through GlobalWorkspaceOrmManager.getRepository (v2) instead of v1 iterator datasource.
packages/twenty-server/src/database/commands/upgrade-version-command/2-20/2-20-workspace-command-1783526282685-backfill-workflow-version-to-core.command.ts Switches the skip-guard to the shared predicate for v2 error compatibility.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 52 to 56
workspaceWorkflows = await workflowRepository.find();
} catch (error) {
if (error instanceof EntityMetadataNotFoundError) {
if (isWorkspaceObjectNotFoundError(error)) {
this.logger.log(
`workflow object does not exist for workspace ${workspaceId}, skipping`,
Comment on lines 55 to 59
workspaceWorkflowVersions = await workflowVersionRepository.find();
} catch (error) {
if (error instanceof EntityMetadataNotFoundError) {
if (isWorkspaceObjectNotFoundError(error)) {
this.logger.log(
`workflowVersion object does not exist for workspace ${workspaceId}, skipping`,
Comment on lines 51 to 55
.count();
} catch (error) {
if (error instanceof EntityMetadataNotFoundError) {
if (isWorkspaceObjectNotFoundError(error)) {
return;
}
Comment on lines +12 to +15
export const isWorkspaceObjectNotFoundError = (error: unknown): boolean =>
error instanceof EntityMetadataNotFoundError ||
(error instanceof TwentyOrmV2Exception &&
error.code === TwentyOrmV2ExceptionCode.UNKNOWN_OBJECT);
@charlesBochet
charlesBochet merged commit bdc9618 into main Aug 25, 2026
140 of 144 checks passed
@charlesBochet
charlesBochet deleted the charles/fix-orm-v2-upgrade-command-object-guards branch August 25, 2026 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants