twentyhq/twenty · critical · Error
BackfillMetadataOverrides: "isActive" changed on "core"."${t
Error message
BackfillMetadataOverrides: "isActive" changed on "core"."${table}" (${activeCountBefore} -> ${activeCountAfter}), aborting. What it means
Thrown by the 2.19 slow instance command that backfills the overrides column from standardOverrides when the count of active rows changes between the before- and after-UPDATE measurements. The migration is designed to be pure data movement (copying standardOverrides into overrides for null overrides rows), so any change in active row count means concurrent activation/deactivation happened during the run, and the migration aborts to avoid an inconsistent result.
Source
Thrown at packages/twenty-server/src/database/commands/upgrade-version-command/2-19/2-19-instance-command-slow-1782986476000-backfill-metadata-overrides.ts:23
const TABLES = ['objectMetadata', 'fieldMetadata'] as const;
@RegisteredInstanceCommand('2.19.0', 1782986476000, { type: 'slow' })
export class BackfillMetadataOverridesSlowInstanceCommand
implements SlowInstanceCommand
{
async runDataMigration(dataSource: DataSource): Promise<void> {
for (const table of TABLES) {
const activeCountBefore = await this.getActiveCount(dataSource, table);
await dataSource.query(
`UPDATE "core"."${table}" SET "overrides" = "standardOverrides" WHERE "standardOverrides" IS NOT NULL AND "overrides" IS NULL`,
);
const activeCountAfter = await this.getActiveCount(dataSource, table);
if (activeCountBefore !== activeCountAfter) {
throw new Error(
`BackfillMetadataOverrides: "isActive" changed on "core"."${table}" (${activeCountBefore} -> ${activeCountAfter}), aborting.`,
);
}
}
}
public async up(_queryRunner: QueryRunner): Promise<void> {
return;
}
public async down(_queryRunner: QueryRunner): Promise<void> {
return;
}
private async getActiveCount(
dataSource: DataSource,
table: (typeof TABLES)[number],
): Promise<number> {View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Run slow instance migrations in a maintenance window with the API server stopped or with workspace mutations paused.
- Re-run the slow instance command after the concurrency source is gone; the UPDATE is idempotent for null-overrides rows.
- If the count drift is persistent, audit for stale workspace-deactivation jobs or scheduled cleanups that flip isActive.
- Confirm only one upgrade runner is active (check for orphaned runners).
Example fix
// before: slow migration runs while API serves traffic // after: stop API, run migration, restart // process: yarn workspace twenty-server stop && npx nx run twenty-server:database:migrate:prod && yarn workspace twenty-server start
Defensive patterns
Strategy: validation
Validate before calling
// Preflight: confirm no concurrent process flips isActive during the slow command.
// Pause API / workspace provisioning, then assert counts are stable across two reads.
const before = await dataSource.query(`SELECT count(*)::int AS c FROM core."objectMetadata" WHERE "isActive" = true`);
await sleep(2000);
const after = await dataSource.query(`SELECT count(*)::int AS c FROM core."objectMetadata" WHERE "isActive" = true`);
if (before[0].c !== after[0].c) {
throw new Error('isActive churn detected; run slow migration in a maintenance window');
} Try / catch
// The guard is built into the migration itself. Re-run after quiescing traffic.
try {
await instanceMigration.runDataMigration(dataSource);
} catch (err) {
if (err instanceof Error && err.message.startsWith('BackfillMetadataOverrides:')) {
// quiesce traffic, then re-run; the UPDATE is idempotent for null-overrides rows
await waitForQuietPeriod();
throw err;
}
throw err;
} Prevention
- Run slow instance migrations in a maintenance window with the API server stopped.
- Ensure only one upgrade runner is active (kill orphans before starting).
- Disable scheduled workspace creation/deactivation during the migration window.
- The UPDATE is idempotent for null-overrides rows, so re-running after quiescing is safe.
When it happens
Trigger: Concurrent writes to core.objectMetadata or core.fieldMetadata during the slow instance migration that flip isActive on any row; another upgrade process, a workspace creation, or an object/field delete operation running in parallel with the slow command's runDataMigration.
Common situations: Running the slow instance migration while the API server is still serving traffic that creates/deactivates objects or fields; running two upgrade runners at once; long-running data migration overlapped with active workspace provisioning.
Related errors
- on-opportunity-partner-assigned: ${failed} person clear(s) f
- on-opportunity-partner-assigned: ${failed} person stamp(s) f
- link-partner-user: ${failed} cascade write(s) failed for ${p
- Failed to update search command menu item labels for workspa
- Failed to add Send Email record-selection commands for works
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/7ad70c4c2e5e1656.
Report an issue: GitHub.