twentyhq/twenty · critical · Error

Failed to add NOT_RECORDED to CallRecording status metadata

Error message

Failed to add NOT_RECORDED to CallRecording status metadata for workspace ${workspaceId}: ${JSON.stringify(validateAndBuildResult, null, 2)}

What it means

Thrown by the same 2.26 command (add-not-recorded-call-recording-status) after it builds the updatedStatusField with the appended NOT_RECORDED option and submits it through validateBuildAndRunLegacyWorkspaceMigration. The orchestrator returned status === 'fail', meaning one or more flat-field validations or the generated SQL migration could not be built/applied. The thrown message embeds the full WorkspaceMigrationOrchestratorFailedResult (status + per-metadata-name report of FailedFlatEntityValidation entries), which names the exact rule and entity that failed.

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:155

    const validateAndBuildResult =
      await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunLegacyWorkspaceMigration(
        {
          isSystemBuild: true,
          applicationUniversalIdentifier:
            twentyStandardFlatApplication.universalIdentifier,
          workspaceId,
          allFlatEntityOperationByMetadataName: {
            fieldMetadata: {
              flatEntityToCreate: [],
              flatEntityToDelete: [],
              flatEntityToUpdate: [updatedStatusField],
            },
          },
        },
      );

    if (validateAndBuildResult.status === 'fail') {
      throw new Error(
        `Failed to add NOT_RECORDED to CallRecording status metadata for workspace ${workspaceId}: ${JSON.stringify(
          validateAndBuildResult,
          null,
          2,
        )}`,
      );
    }

    this.logger.log(
      `Added NOT_RECORDED to CallRecording status metadata for workspace ${workspaceId}`,
    );
  }
}

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Read the JSON report in the thrown message — it lists, per metadata name, each FailedFlatEntityValidation (entity universalIdentifier + error code).
  2. If the report shows a duplicate-option/id conflict, remove the stray option row for that field in the workspace metadata so the append is clean.
  3. Force a cache recompute for the workspace (the command uses workspaceCacheService.getOrRecompute; invalidate and re-run) so the build sees consistent state.
  4. Re-run the single 2.26 command for the workspace once the conflict is cleared.
Defensive patterns

Strategy: try-catch

Validate before calling

// Idempotency pre-check the command already does, but harden against id/value drift:
const currentOptions = (selectStatusField.options ?? []);
const hasId = currentOptions.some(o => o.id === NOT_RECORDED_STATUS_OPTION.id);
const hasValue = currentOptions.some(o => o.value === CallRecordingStatus.NOT_RECORDED);
if (hasId || hasValue) { /* reconcile before submitting the update */ }

Try / catch

try {
  await command.runOnWorkspace({ workspaceId, options });
} catch (e) {
  const report = JSON.parse(e.message.split(':').slice(1).join(':').trim());
  // report.report.fieldMetadata[] -> [{ universalIdentifier, errorCode }]
  logger.error({ workspaceId, report }, '2.26 NOT_RECORDED upgrade failed');
  // continue to next workspace rather than aborting the whole upgrade
}

Prevention

When it happens

Trigger: The NOT_RECORDED option collides (duplicate id/value with an existing option), the computed nextOptionPosition conflicts, the status field's options array fails the select-field validator, or a dependent relation/view referencing the field blocks the metadata update. Also fires if the workspace cache is stale relative to the live metadata and the build detects an inconsistency.

Common situations: A workspace that already has a partially-added NOT_RECORDED (id or value present but the early `hasNotRecordedStatus` check missed it due to a value/label mismatch); options with non-unique ids from a prior manual insert; a workspace whose metadata cache was not invalidated after an out-of-band DB edit.

Related errors


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