{"record":{"id":"3db8304e58265fe3","repo":"n8n-io/n8n","slug":"down-migration-only-possible-when-there-are-no-pro","errorCode":null,"errorMessage":"Down migration only possible when there are no projects. Please delete all projects that were created via the UI first.","messagePattern":"Down migration only possible when there are no projects\\. Please delete all projects that were created via the UI first\\.","errorType":"exception","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts","lineNumber":246,"sourceCode":"\t\tawait this.alterSharedTable(table.sharedCredentials, context);\n\t\tawait this.alterSharedCredentials(context);\n\t\tawait this.alterSharedTable(table.sharedWorkflow, context);\n\t\tawait this.alterSharedWorkflow(context);\n\t}\n\n\tasync down({ logger, escape, runQuery, schemaBuilder: sb }: MigrationContext) {\n\t\tconst { t, c } = escapeNames(escape);\n\n\t\t// 0. check if all projects are personal projects\n\t\tconst [{ count: nonPersonalProjects }] = await runQuery<[{ count: number }]>(\n\t\t\t`SELECT COUNT(*) FROM ${t.project} WHERE type <> 'personal';`,\n\t\t);\n\n\t\tif (nonPersonalProjects > 0) {\n\t\t\tconst message =\n\t\t\t\t'Down migration only possible when there are no projects. Please delete all projects that were created via the UI first.';\n\t\t\tlogger.error(message);\n\t\t\tthrow new UserError(message);\n\t\t}\n\n\t\t// 1. create temp table for shared workflows\n\t\tawait sb\n\t\t\t.createTable(table.sharedWorkflowTemp)\n\t\t\t.withColumns(\n\t\t\t\tsb.column('workflowId').varchar(36).notNull.primary,\n\t\t\t\tsb.column('userId').uuid.notNull.primary,\n\t\t\t\tsb.column('role').text.notNull,\n\t\t\t)\n\t\t\t.withForeignKey('workflowId', {\n\t\t\t\ttableName: 'workflow_entity',\n\t\t\t\tcolumnName: 'id',\n\t\t\t\tonDelete: 'CASCADE',\n\t\t\t\tname: undefined,\n\t\t\t})\n\t\t\t.withForeignKey('userId', {\n\t\t\t\ttableName: table.user,","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts#L228-L264","documentation":"UserError thrown by CreateProject migration 1714133768519.down() if any non-personal projects exist when the user attempts to roll back. The down migration can only revert when only personal projects remain, because shared/project workflows created via the UI cannot be safely unmigrated. Logged at error level before throwing.","triggerScenarios":"Running `n8n migration:revert` (or a down migration tool) on a DB where users have created non-personal projects (team/community projects). The check counts rows in the project table with type <> 'personal' and refuses if > 0.","commonSituations":"Attempting to downgrade n8n across the project-acl boundary after users adopted shared projects; rolling back a failed upgrade without first cleaning up team projects; restoring an upgraded DB and trying to revert.","solutions":["Before reverting, delete all non-personal (team/community) projects via the n8n UI so only personal projects remain.","If reverting is impossible, restore from a pre-migration backup instead of running the down migration.","Document that this migration is effectively irreversible once shared projects exist — plan upgrades accordingly.","For dev environments, wipe the DB and re-seed rather than reverting."],"exampleFix":"// before\nn8n migration:revert --all\n\n// after\n# 1. in the n8n UI, delete every team/community project\n# 2. confirm only personal projects remain, then\nn8n migration:revert","handlingStrategy":"validation","validationCode":"const nonPersonal = await runQuery(`SELECT COUNT(*) FROM project WHERE type <> 'personal';`);\nif (nonPersonal > 0) {\n  // do not attempt the down migration; clean up or restore instead\n}","typeGuard":null,"tryCatchPattern":"try {\n  await migrationRevert();\n} catch (err) {\n  if (err instanceof UserError && /Down migration only possible when there are no projects/.test(err.message)) {\n    // surface: delete non-personal projects first, or restore from backup\n  } else throw err;\n}","preventionTips":["Before reverting this migration, delete all non-personal projects via the UI.","Prefer restoring from a pre-migration backup over running irreversible down migrations.","Treat the project-ACL migration as effectively irreversible once shared projects exist."],"tags":["migration","projects","downgrade","rbac"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}