twentyhq/twenty · critical · Error

CallRecording status metadata is not a SELECT field for work

Error message

CallRecording status metadata is not a SELECT field for workspace ${workspaceId}

What it means

Thrown by the 2.26 workspace upgrade command that adds the NOT_RECORDED option to the CallRecording.status select field. After confirming the CallRecording object and its status field both exist, it asserts statusField.type === FieldMetadataType.SELECT before casting and appending an option. The throw signals that the workspace's status field metadata has drifted from the standard definition (which declares it as SELECT) — almost always manual edits, a half-applied earlier migration, or a custom override.

Source

Thrown at packages/twenty-server/src/database/commands/upgrade-version-command/2-26/2-26-workspace-command-1785334800000-add-not-recorded-call-recording-status.command.ts:89

      return;
    }

    const statusField =
      flatFieldMetadataMaps.byUniversalIdentifier[
        CALL_RECORDING_STATUS_FIELD_UNIVERSAL_IDENTIFIER
      ];

    if (!isDefined(statusField)) {
      this.logger.log(
        `CallRecording status field metadata does not exist for workspace ${workspaceId}, skipping`,
      );

      return;
    }

    if (statusField.type !== FieldMetadataType.SELECT) {
      throw new Error(
        `CallRecording status metadata is not a SELECT field for workspace ${workspaceId}`,
      );
    }

    const selectStatusField =
      statusField as FlatFieldMetadata<FieldMetadataType.SELECT>;
    const currentOptions = selectStatusField.options ?? [];
    const hasNotRecordedStatus = currentOptions.some(
      (option) => option.value === CallRecordingStatus.NOT_RECORDED,
    );

    if (hasNotRecordedStatus) {
      this.logger.log(
        `CallRecording status metadata already has NOT_RECORDED for workspace ${workspaceId}, skipping`,
      );

      return;
    }

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Query the workspace metadata: SELECT type FROM core.fieldMetadata WHERE universalIdentifier = '<callRecording.status UI>' for the failing workspaceId to see the actual stored type.
  2. If the field was manually repurposed, restore it to type = 'SELECT' (or rename/drop the custom field and let the standard one be re-seeded) before re-running the upgrade.
  3. Re-run the command for just that workspace: npx nx run twenty-server:database:migrate:prod scoped to the 2.26 command.
  4. If the field genuinely should not be SELECT in this workspace, mark the workspace upgrade as handled and skip — but verify no downstream code depends on status being a select.

Example fix

// before — stored metadata has type drift
// statusField.type === 'TEXT'  -> throws

// fix in DB (restore standard type), then the command proceeds:
//   UPDATE core.fieldMetadata SET type = 'SELECT'
//   WHERE "universalIdentifier" =
//     STANDARD_OBJECTS.callRecording.fields.status.universalIdentifier;
// then re-run the 2.26 workspace command.
Defensive patterns

Strategy: validation

Validate before calling

// Before running the 2.26 upgrade for a workspace, verify the status field type:
const statusField = flatFieldMetadataMaps.byUniversalIdentifier[
  CALL_RECORDING_STATUS_FIELD_UNIVERSAL_IDENTIFIER,
];
if (isDefined(statusField) && statusField.type !== FieldMetadataType.SELECT) {
  // repair or skip this workspace before invoking the command
}

Type guard

import { FieldMetadataType } from 'twenty-shared/types';

const isSelectField = (
  field: { type: FieldMetadataType } | undefined,
): field is { type: FieldMetadataType.SELECT; options?: unknown[] } =>
  field?.type === FieldMetadataType.SELECT;

Prevention

When it happens

Trigger: The command runs per-workspace during the 2.26.0 upgrade. It loads statusField from flatFieldMetadataMaps by CALL_RECORDING_STATUS_FIELD_UNIVERSAL_IDENTIFIER, and the stored type is anything other than SELECT (e.g. it was changed to a multi-select / text / relation, or the column was repurposed). It also fires if the field was re-created with a different type after a botched prior upgrade.

Common situations: A workspace where an admin or a prior custom migration changed the CallRecording.status field type; schema drift between the core metadata tables and the standard definition; an interrupted 2.26 run that left the field half-modified; imports from another CRM that overwrote the status column type.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/26143095f8bd8556. Report an issue: GitHub.