twentyhq/twenty · critical · Error
Failed to gate default command menu items by permission flag
Error message
Failed to gate default command menu items by permission flag for workspace ${workspaceId} What it means
Thrown by the 2.8 workspace upgrade command that gates default command menu items behind a permission flag. It fires only after the command has already attempted a legacy workspace migration via workspaceMigrationValidateBuildAndRunService.validateBuildAndRunLegacyWorkspaceMigration, and that service returned status === 'fail'. The migration service validates, builds, and runs flat-entity operations (here: commandMenuItem updates); a failure means the operation set did not pass validation or could not be built into a runnable migration for that workspace.
Source
Thrown at packages/twenty-server/src/database/commands/upgrade-version-command/2-8/2-8-workspace-command-1798100010000-gate-default-command-menu-items-by-permission-flag.command.ts:150
allFlatEntityOperationByMetadataName: {
commandMenuItem: {
flatEntityToCreate: [],
flatEntityToDelete: [],
flatEntityToUpdate: itemsToUpdate,
},
},
workspaceId,
applicationUniversalIdentifier:
twentyStandardFlatApplication.universalIdentifier,
},
);
if (validateAndBuildResult.status === 'fail') {
this.logger.error(
`Failed to update command menu item availability expressions:\n${JSON.stringify(validateAndBuildResult, null, 2)}`,
);
throw new Error(
`Failed to gate default command menu items by permission flag for workspace ${workspaceId}`,
);
}
this.logger.log(
`Successfully updated ${itemsToUpdate.length} command menu item availability expression(s) for workspace ${workspaceId}`,
);
}
}
View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Read the preceding log line — `Failed to update command menu item availability expressions:` followed by the JSON dump — to get the exact validation/build error from the migration service.
- Inspect that workspace's commandMenuItem table (schema: the workspace's core schema) for rows missing fields the build expects, or rows whose id/key no longer match the standard command definitions.
- Re-run the upgrade command for the single failing workspace with --verbose to capture the full migration build trace, then fix the offending metadata row directly.
- If the workspace metadata is irreparably drifted, restore from backup or reset the workspace metadata to the standard set before re-running the upgrade.
- Verify the twentyStandardFlatApplication.universalIdentifier constant matches what the workspace was originally provisioned with.
Example fix
// before — throw with only workspaceId context, root cause only in a separate log line above
if (validateAndBuildResult.status === 'fail') {
this.logger.error(`Failed to update...:\n${JSON.stringify(validateAndBuildResult, null, 2)}`);
throw new Error(`Failed to gate default command menu items by permission flag for workspace ${workspaceId}`);
}
// after — embed the structured failure detail in the thrown message so operators see root cause in stack traces
type MigrationFail = { status: 'fail'; error?: string; message?: string; details?: unknown };
const fail = validateAndBuildResult as MigrationFail;
throw new Error(
`Failed to gate default command menu items by permission flag for workspace ${workspaceId}: ` +
`${fail.error ?? fail.message ?? 'see preceding log for full validateAndBuildResult'}`,
); Defensive patterns
Strategy: try-catch
Validate before calling
// Before invoking the upgrade runner for a workspace, sanity-check the commandMenuItem rows the command will touch.
// (Read-only check; run in the same transaction scope the upgrade uses.)
const items = await dataSource.query(
`SELECT id, "key", "conditionalAvailabilityExpression" FROM ${workspaceSchema}.commandMenuItem WHERE "key" = ANY($1)`,
[requiredKeys],
);
if (items.length < requiredKeys.length) {
const missing = requiredKeys.filter(k => !items.some(i => i.key === k));
throw new Error(`commandMenuItem rows missing for keys: ${missing.join(', ')}`);
} Type guard
// Narrow the migration result so the fail branch is statically known.
type ValidateBuildAndRunResult =
| { status: 'success' }
| { status: 'fail'; error?: string; message?: string; details?: unknown };
function isMigrationFail(r: ValidateBuildAndRunResult): r is Extract<ValidateBuildAndRunResult, { status: 'fail' }> {
return r.status === 'fail';
} Try / catch
try {
await upgradeCommand.run();
} catch (err) {
if (err instanceof Error && err.message.startsWith('Failed to gate default command menu items')) {
// log workspaceId, mark the workspace upgrade as failed-but-resumable, continue other workspaces
logger.error({ workspaceId, err: err.message }, 'command-menu gate failed; workspace skipped');
failedWorkspaceIds.push(workspaceId);
} else {
throw err;
}
} Prevention
- Run upgrade commands against a restored backup of production in staging first, so metadata drift surfaces before prod.
- Keep instance commands in sequence — do not skip versions between major upgrades.
- Capture the preceding structured log line (validateAndBuildResult JSON) in your upgrade runner's error reporter so root cause travels with the alert.
When it happens
Trigger: Running the 2.8 upgrade (`database:migrate:prod` or the upgrade runner iterating workspaces) against a workspace whose commandMenuItem records are in an unexpected state — e.g. an item referenced by the command no longer exists, a flat-entity field is missing/invalid, or the applicationUniversalIdentifier for twentyStandardFlatApplication does not match the workspace's stored metadata. Also triggered when the underlying migration build throws or the DB transaction aborts mid-run.
Common situations: Upgrading a self-hosted instance that skipped intermediate versions (so its metadata schema is partially drifted), running the upgrade against a workspace with manually-edited or corrupted command menu item metadata, or a partial previous run that left commandMenuItem rows half-updated. The logged JSON.stringify(validateAndBuildResult) immediately before the throw contains the precise failure reason.
Related errors
- Failed to backfill FIELDS widgets for workspace ${workspaceI
- Failed to sync CallRecording navigation command menu item av
- Failed to update search command menu item labels for workspa
- Failed to add Send Email record-selection commands for works
- Failed to backfill standard skills for workspace ${workspace
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/2272c01331225b61.
Report an issue: GitHub.