twentyhq/twenty · error · Error

Failed to persist searchFieldMetadata rows for workspace ${w

Error message

Failed to persist searchFieldMetadata rows for workspace ${workspaceId}

What it means

Thrown by the 2.16 backfill-search-field-metadata command when validateAndBuildResult.status === 'fail' while persisting searchFieldMetadata rows for an application. The logger.error above prints per-application context; the thrown error is workspace-scoped. searchFieldMetadata drives full-text search indexing, so a build failure here means the search payload did not pass validation.

Source

Thrown at packages/twenty-server/src/database/commands/upgrade-version-command/2-16/2-16-workspace-command-1799100000000-backfill-search-field-metadata.command.ts:154

                flatEntityToDelete: [],
                flatEntityToUpdate: [],
              },
            },
            workspaceId,
            applicationUniversalIdentifier,
          },
        );

      if (validateAndBuildResult.status === 'fail') {
        this.logger.error(
          `Failed to persist searchFieldMetadata rows for application ${applicationUniversalIdentifier}:\n${JSON.stringify(
            validateAndBuildResult,
            null,
            2,
          )}`,
        );

        throw new Error(
          `Failed to persist searchFieldMetadata rows for workspace ${workspaceId}`,
        );
      }
    }

    this.logger.log(
      `Successfully backfilled ${totalRowsToCreate} searchFieldMetadata row(s) for workspace ${workspaceId}`,
    );
  }
}

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Read the per-application logger.error line to find which applicationUniversalIdentifier failed.
  2. Inspect the JSON in that log to see which searchFieldMetadata rows failed and why.
  3. Verify the referenced fieldMetadata rows exist and are active for that application; reactivate or repoint them.
  4. Re-run the workspace upgrade for that workspace.
Defensive patterns

Strategy: validation

Validate before calling

// For each application, confirm referenced fieldMetadata rows exist and are active
// before persisting searchFieldMetadata rows.
const dangling = await dataSource.query(`
  SELECT s."id" FROM core."searchFieldMetadata" s
  LEFT JOIN core."fieldMetadata" f ON f."id" = s."fieldMetadataId"
  WHERE f."id" IS NULL OR f."isActive" = false
`);
if (dangling.length) throw new Error(`Dangling search refs: ${JSON.stringify(dangling)}`);

Type guard

function isFailResult(r: unknown): r is { status: 'fail' } {
  return typeof r === 'object' && r !== null && (r as any).status === 'fail';
}

Try / catch

for (const app of apps) {
  try {
    const res = await service.validateBuildAndRunLegacyWorkspaceMigration(payloadFor(app));
    if (res.status === 'fail') throw new Error(`... for workspace ${workspaceId}`);
  } catch (err) { upgradeAudit.record(workspaceId, app.id, err); throw err; }
}

Prevention

When it happens

Trigger: Running the 2.16 upgrade where the application's fieldMetadata referenced by the search rows is missing/inactive, or the flatEntityToCreate payload references a fieldMetadataId that the validator cannot resolve; happens per-application inside the loop, so the offending applicationUniversalIdentifier is in the log line just above.

Common situations: Application with deleted/deactivated fields whose search rows still try to reference them; image whose standard-application seed does not match the workspace; partial prior run leaving duplicate searchFieldMetadata rows.

Related errors


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