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
- Query the workspace metadata: SELECT type FROM core.fieldMetadata WHERE universalIdentifier = '<callRecording.status UI>' for the failing workspaceId to see the actual stored type.
- 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.
- Re-run the command for just that workspace: npx nx run twenty-server:database:migrate:prod scoped to the 2.26 command.
- 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
- Do not manually change standard field types; if a field must be repurposed, create a custom field instead.
- Run upgrades on a DB backup so a drifted standard field can be restored.
- Before upgrading, diff workspace standard field types against the standard definition for the affected objects.
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
- Failed to add NOT_RECORDED to CallRecording status metadata
- Failed to add the CalendarEvent Call Recording tab for works
- CallRecording status metadata is not a SELECT field for work
- Failed to sync CallRecording status metadata for workspace $
- Failed to backfill standard skills for workspace ${workspace
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/26143095f8bd8556.
Report an issue: GitHub.