{"record":{"id":"3feeec803c8b5ed9","repo":"remix-run/remix","slug":"migration-checksum-drift-detected-for-row-id","errorCode":null,"errorMessage":"Migration checksum drift detected for \"{row.id}\" (journal={row.checksum}, current={expected})","messagePattern":"Migration checksum drift detected for \"(.+?)\" \\(journal=(.+?), current=(.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/data-table/src/lib/migrations/runner.ts","lineNumber":117,"sourceCode":"  for (let row of journal) {\n    let migration = migrationMap.get(row.id)\n\n    if (!migration) {\n      // Rolling back must stay possible when journal rows have no matching\n      // migration files, so only forward runs hard-error on orphaned entries.\n      if (direction === 'down') {\n        continue\n      }\n\n      throw new Error(\n        'Applied migration \"' + row.id + '_' + row.name + '\" is missing from current migrations',\n      )\n    }\n\n    let expected = await computeChecksum(migration)\n\n    if (expected !== row.checksum) {\n      throw new Error(\n        'Migration checksum drift detected for \"' +\n          row.id +\n          '\" (journal=' +\n          row.checksum +\n          ', current=' +\n          expected +\n          ')',\n      )\n    }\n  }\n}\n\nfunction resolveTransactionMode(migration: MigrationDescriptor): MigrationTransactionMode {\n  if (migration.transaction) {\n    return migration.transaction\n  }\n\n  let directive = parseTransactionDirective(migration.up)","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table/src/lib/migrations/runner.ts#L99-L135","documentation":"A journal row's stored checksum no longer matches the checksum computed from the current migration file. This means an already-applied migration was edited after being applied, so the journal history and the source of truth have diverged; the runner halts the forward run.","triggerScenarios":"Editing a migration file's SQL/content after it was applied and then running `direction: 'up'`; reformatting or line-ending changes that alter the bytes hashed by computeChecksum during assertMigrationIntegrity.","commonSituations":"Fixing a typo directly in an old migration; a formatter/linter rewriting migration files on save or in CI; inconsistent line endings (CRLF vs LF) across machines.","solutions":["Revert the edited migration file to its applied content (check git history for the original).","If the edit was intentional, recreate the environment: roll back the migration and re-apply, or drop/rebuild the database in dev.","As a last resort, update the journal row's checksum to the new computed value — only when you are certain the change is safe and all environments get the same file.","Exclude migration files from formatters and normalize line endings (.gitattributes `* text=auto eol=lf`)."],"exampleFix":"# before: edited applied migration in place\n# 20240101123045_create_users/migration.sql  (modified)\n\n# after: restore original\n git checkout <last-applied-commit> -- path/to/migration.sql\n# or (dev only) rebuild from scratch:\n#  dropdb && recreatedb && runMigrations up","handlingStrategy":"try-catch","validationCode":"for (let row of await db.select().from(journalTable)) {\n  let migration = registry.list().find((m) => m.id === row.id)\n  if (migration && (await computeChecksum(migration)) !== row.checksum) {\n    throw new Error(`file for ${row.id} has drifted from the applied version`)\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runMigrations(db, { direction: 'up' })\n} catch (error) {\n  if (error instanceof Error && error.message.includes('checksum drift')) {\n    // diff the file vs git history; restore original or rebuild the database\n  }\n  throw error\n}","preventionTips":["Treat applied migrations as immutable once committed.","Exclude migration files from formatters and enforce LF line endings via .gitattributes.","Run a checksum verification step in CI against a scratch database."],"tags":["migrations","checksum","integrity","journal"],"backgroundTag":"checksum-mismatch","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}