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
- Read the per-application logger.error line to find which applicationUniversalIdentifier failed.
- Inspect the JSON in that log to see which searchFieldMetadata rows failed and why.
- Verify the referenced fieldMetadata rows exist and are active for that application; reactivate or repoint them.
- 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
- Keep application fieldMetadata and searchFieldMetadata consistent; never hard-delete one without the other.
- Deactivate rather than delete when fields have search rows.
- Run upgrades with API mutations paused.
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
- Failed to backfill standard skills for workspace ${workspace
- Migration failed for workspace ${workspaceId} while healing
- Failed to create CallRecording recordingRequestStatus metada
- Failed to delete CalendarEvent recordingPreference field for
- Failed to create CalendarEvent record page metadata for work
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/99e6049af45b7efd.
Report an issue: GitHub.