{"record":{"id":"0cc54f97b7c162fb","repo":"strapi/strapi","slug":"unresolved-differences-in-schema-review-workflows","errorCode":null,"errorMessage":"Unresolved differences in schema [review workflows]","messagePattern":"Unresolved differences in schema \\[review workflows\\]","errorType":"panic","errorClass":"TransferEngineInitializationError","httpStatus":null,"severity":"critical","filePath":"packages/core/strapi/src/cli/utils/data-transfer.ts","lineNumber":587,"sourceCode":"            source\n          );\n        } else if (diff.kind === 'modified') {\n          engine.reportWarning(chalk.red(`${chalk.bold(path)} has a different data type`), source);\n        }\n      }\n    });\n\n    // output the known feature warnings\n    if (workflowsStatus === 'added') {\n      engine.reportWarning(chalk.red(`Review workflows feature does not exist on source`), source);\n    } else if (workflowsStatus === 'deleted') {\n      engine.reportWarning(\n        chalk.red(`Review workflows feature does not exist on destination`),\n        source\n      );\n    } else if (workflowsStatus === 'modified') {\n      engine.panic(\n        new TransferEngineInitializationError('Unresolved differences in schema [review workflows]')\n      );\n    }\n\n    const confirmed = await confirmMessage(\n      'There are differences in schema between the source and destination, and the data listed above will be lost. Are you sure you want to continue?',\n      {\n        force,\n      }\n    );\n\n    // reset handler back to normal\n    setSignalHandler(() => abortTransfer({ engine, strapi: strapi as Core.Strapi }));\n\n    if (confirmed) {\n      context.ignoredDiffs = merge(context.diffs, context.ignoredDiffs);\n    }\n\n    return next(context);","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/strapi/strapi/blob/4a4101264d7098754df36e85fa629fd2f2349d8c/packages/core/strapi/src/cli/utils/data-transfer.ts#L569-L605","documentation":"Thrown by the CLI schema-diff handler (core/strapi/src/cli/utils/data-transfer.ts:587) during `strapi import` / restore integrity check. When diffing source vs destination schemas, review-workflows-related UIDs (plugin::review-workflows.workflow, plugin::review-workflows.workflow-stage, or any attribute whose path ends with strapi_stage / strapi_assignee) are tracked separately. If the diff kind is 'modified' (the schema SHAPE differs — a column type, attribute definition, or stage structure changed between the two sides) the handler raises a TransferEngineInitializationError (SeverityKind.FATAL) via engine.panic(). Unlike 'added'/'deleted' which only warn and can be overridden with --force / the confirm prompt, 'modified' is a hard stop that fires BEFORE the confirmMessage call, so it cannot be bypassed by --force.","triggerScenarios":"Running `strapi import` (or a programmatic TransferEngine transfer using getDiffHandler) where both source and destination have the review-workflows plugin enabled, but the workflow / workflow-stage content type definitions differ. The diff loop sets workflowsStatus='modified' for any of: plugin::review-workflows.workflow, plugin::review-workflows.workflow-stage, or attributes strapi_stage* / strapi_assignee* whose diff.kind === 'modified'. engine.panic() then throws TransferEngineInitializationError during the initialization step.","commonSituations":"Source and destination run different versions of the review-workflows plugin (the workflow-stage schema gained/changed columns across releases). Review-workflows enabled on both Strapi environments but one has custom stages / stage schema customizations. Importing an export file produced by a newer Strapi into an older destination (or vice versa). Migrating between CE and EE where the review-workflows feature presence differs in shape rather than existence.","solutions":["Align the review-workflows plugin version (and Strapi version) between source and destination so the workflow / workflow-stage schemas are byte-identical, then regenerate the export and re-run import.","If you do not need review workflows on this transfer, disable the review-workflows plugin on BOTH sides before exporting/importing — this moves the diff to 'added'/'deleted' (warn-only, overridable with --force).","Inspect the actual modified attributes: dump `context.diffs` for the two review-workflows UIDs (or run import with STRAPI_DEBUG=true) to see which column (strapi_stage, strapi_assignee, etc.) changed type, then reconcile that column on the destination.","On the destination, run `strapi cs:diff` (or compare content-types) against the source to confirm the review-workflows content types match before retrying the transfer.","If the source is authoritative, restore the destination's review-workflows content type definitions to match the source (same attributes/types), restart Strapi so the DB schema syncs, then re-import."],"exampleFix":"// before — both sides enabled, schema drifted (workflow-stage gained a column)\n//   strapi import --file export.tar.gz\n//   -> TransferEngineInitializationError: Unresolved differences in schema [review workflows]\n\n// after — align versions / disable the plugin on both sides, then re-export & import\n// 1) On source and destination, pin the same plugin version in package.json\n//    \"@strapi/plugin-review-workflows\": \"5.x.y\"\n// 2) OR disable on both before transfer:\n//    config/plugins.ts -> 'review-workflows': { enabled: false }\n// 3) Regenerate the export from source, then:\n//    strapi import --file export.tar.gz","handlingStrategy":"validation","validationCode":"// Before running `strapi import` / engine.transfer(), compare the\n// review-workflows content-type schemas on source and destination. Abort early\n// with an actionable message instead of letting the diff handler panic.\nimport { diff } from 'deep-diff';\n\nconst RW_UIDS = [\n  'plugin::review-workflows.workflow',\n  'plugin::review-workflows.workflow-stage',\n];\n\nfunction reviewWorkflowsSchemaIsCompatible(\n  sourceSchemas: Record<string, Struct.Schema>,\n  destSchemas: Record<string, Struct.Schema>\n): { ok: true } | { ok: false; uids: string[] } {\n  const modified: string[] = [];\n  for (const uid of RW_UIDS) {\n    const a = sourceSchemas[uid];\n    const b = destSchemas[uid];\n    if (a && b && diff(a, b)?.some((d) => d.kind === 'E' || d.kind === 'A')) {\n      modified.push(uid);\n    }\n  }\n  return modified.length === 0 ? { ok: true } : { ok: false, uids: modified };\n}\n\nconst check = reviewWorkflowsSchemaIsCompatible(\n  await sourceProvider.getSchemas() ?? {},\n  await destinationProvider.getSchemas() ?? {}\n);\nif (!check.ok) {\n  throw new Error(\n    `Refusing to transfer: review-workflows schema differs on: ${check.uids.join(', ')}. ` +\n    `Align the @strapi/plugin-review-workflows version on both sides, ` +\n    `or disable the plugin on both sides before exporting.`\n  );\n}","typeGuard":null,"tryCatchPattern":"// The CLI handler raises TransferEngineInitializationError via engine.panic during\n// the integrity check, which propagates from engine.transfer(). Catch that class\n// specifically and emit a schema-alignment hint instead of a raw stack trace.\nimport { TransferEngineInitializationError } from '@strapi/data-transfer/transfer';\n\ntry {\n  await engine.transfer();\n} catch (e) {\n  if (e instanceof TransferEngineInitializationError &&\n      /review workflows/i.test(e.message)) {\n    console.error(\n      'Import aborted: review-workflows schema differs between source and destination.\\n' +\n      'Options:\\n' +\n      '  1. Match the @strapi/plugin-review-workflows version on both environments and re-export.\\n' +\n      '  2. Disable review-workflows on BOTH source and destination, then re-export and re-import.'\n    );\n    process.exitCode = 1;\n    return;\n  }\n  throw e;\n}","preventionTips":["Pin the same @strapi/plugin-review-workflows version on source and destination in package.json — schema drift across plugin versions is the most common trigger.","Run `strapi export` and `strapi import` on identical Strapi major.minor versions; review-workflows stage attributes change between releases.","If you do not need review workflows for a given migration, disable the plugin on both sides before the transfer to fall into the warn-only 'added'/'deleted' branch.","Before importing into a long-lived environment, run `strapi content-types:diff` (or compare schema.json) against the source to catch 'modified' review-workflows attributes ahead of time.","Treat this error as non-retriable: --force cannot bypass it because engine.panic() fires before the confirm prompt. Resolve the schema delta first."],"tags":["data-transfer","review-workflows","schema-diff","import","initialization-error"],"backgroundTag":null,"analyzedSha":"4a4101264d7098754df36e85fa629fd2f2349d8c","analyzedAt":"2026-08-12T12:47:50.760Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}