{"record":{"id":"882543670a7759e5","repo":"twentyhq/twenty","slug":"callrecording-status-metadata-is-not-a-select-fiel","errorCode":null,"errorMessage":"CallRecording status metadata is not a SELECT field for workspace ${workspaceId}","messagePattern":"CallRecording status metadata is not a SELECT field for workspace (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/twenty-server/src/database/commands/upgrade-version-command/2-16/2-16-workspace-command-1799100001000-sync-call-recording-status.command.ts","lineNumber":78,"sourceCode":"\n      return;\n    }\n\n    const statusField =\n      flatFieldMetadataMaps.byUniversalIdentifier[\n        CALL_RECORDING_STATUS_FIELD_UNIVERSAL_IDENTIFIER\n      ];\n\n    if (!isDefined(statusField)) {\n      this.logger.log(\n        `CallRecording status field metadata does not exist for workspace ${workspaceId}, skipping`,\n      );\n\n      return;\n    }\n\n    if (statusField.type !== FieldMetadataType.SELECT) {\n      throw new Error(\n        `CallRecording status metadata is not a SELECT field for workspace ${workspaceId}`,\n      );\n    }\n\n    const selectStatusField =\n      statusField as FlatFieldMetadata<FieldMetadataType.SELECT>;\n    const optionsWithFailedStatus = (selectStatusField.options ?? []).map(\n      (option) =>\n        option.value === LEGACY_FAILED_STATUS\n          ? { ...option, value: FAILED_STATUS }\n          : option,\n    );\n    const hasLegacyFailedStatus = optionsWithFailedStatus.some(\n      (option, index) =>\n        option.value !== selectStatusField.options?.[index]?.value,\n    );\n\n    if (!hasLegacyFailedStatus) {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/twentyhq/twenty/blob/1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6/packages/twenty-server/src/database/commands/upgrade-version-command/2-16/2-16-workspace-command-1799100001000-sync-call-recording-status.command.ts#L60-L96","documentation":"Thrown by the 2.16 sync-call-recording-status command when the CallRecording status field exists but its type is not FieldMetadataType.SELECT. The command's whole purpose is to rewrite the SELECT option value LEGACY_FAILED_STATUS to FAILED_STATUS, so a non-SELECT type makes the rewrite impossible. The status field is located by universal identifier; a missing field is a graceful skip, but a wrong-typed field is a hard error.","triggerScenarios":"Workspace whose CallRecording status fieldMetadata row has type other than SELECT (e.g. mutated to TEXT, or a custom field shadows the standard one). Triggered during the 2.16 upgrade when statusField.type !== SELECT after the isDefined check passes.","commonSituations":"Manual edit of the status field's type in the DB; a prior migration that changed the field type; conflicting custom field sharing the universal identifier.","solutions":["Query core.fieldMetadata for the CallRecording status field (universal identifier CALL_RECORDING_STATUS_FIELD_UNIVERSAL_IDENTIFIER) and inspect its type.","If it was changed erroneously, restore type to SELECT with the expected options payload, then re-run.","If the workspace legitimately has no status field, confirm the isDefined branch above is being hit (it should skip, not throw).","After correcting the type, re-run the 2.16 upgrade for the workspace."],"exampleFix":"-- before\ncore.fieldMetadata: { universalIdentifier: 'status', type: 'TEXT' }\n-- after\nUPDATE core.\"fieldMetadata\" SET \"type\" = 'SELECT' WHERE \"nameSingular\" = 'status' AND \"objectMetadataId\" = (SELECT id FROM core.\"objectMetadata\" WHERE \"nameSingular\" = 'callRecording');","handlingStrategy":"type-guard","validationCode":"// Before the upgrade, confirm the CallRecording status field is SELECT if present.\nconst row = await dataSource.query(`\n  SELECT \"type\" FROM core.\"fieldMetadata\"\n  WHERE \"nameSingular\" = 'status'\n    AND \"objectMetadataId\" = (SELECT id FROM core.\"objectMetadata\" WHERE \"nameSingular\" = 'callRecording')\n`);\nif (row.length && row[0].type !== 'SELECT') {\n  throw new Error(`CallRecording status field type is ${row[0].type}, expected SELECT`);\n}","typeGuard":"import { FieldMetadataType } from '@twenty/shared';\n\nfunction isSelectField(field: { type: FieldMetadataType } | undefined | null): field is { type: FieldMetadataType.SELECT } {\n  return isDefined(field) && field.type === FieldMetadataType.SELECT;\n}","tryCatchPattern":"if (!isSelectField(statusField)) {\n  throw new Error(`CallRecording status metadata is not a SELECT field for workspace ${workspaceId}`);\n}","preventionTips":["Never change a standard SELECT field's type manually in the DB.","Detect and report type drift on standard fields before upgrade via a preflight check.","Keep custom fields from reusing standard universal identifiers."],"tags":["migration","workspace-upgrade","type-mismatch","call-recording","select-field"],"backgroundTag":null,"analyzedSha":"1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6","analyzedAt":"2026-08-12T15:37:27.593Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}