{"record":{"id":"65860d047c3471b4","repo":"remix-run/remix","slug":"migration-script-declares-more-than-one-transactio","errorCode":null,"errorMessage":"Migration script declares more than one transaction directive","messagePattern":"Migration script declares more than one transaction directive","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/data-table/src/lib/migrations/directive.ts","lineNumber":31,"sourceCode":" */\nexport function parseTransactionDirective(sql: string): MigrationTransactionMode | undefined {\n  let match: MigrationTransactionMode | undefined\n\n  for (let line of sql.split(/\\r?\\n/)) {\n    let trimmed = line.trim()\n\n    if (!trimmed.startsWith('--')) {\n      continue\n    }\n\n    let result = directivePattern.exec(trimmed)\n\n    if (!result) {\n      continue\n    }\n\n    if (match !== undefined) {\n      throw new Error('Migration script declares more than one transaction directive')\n    }\n\n    match = result[1].toLowerCase() as MigrationTransactionMode\n  }\n\n  return match\n}\n","sourceCodeStart":13,"sourceCodeEnd":39,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table/src/lib/migrations/directive.ts#L13-L39","documentation":"The migration script parser found two or more transaction directives (e.g. `-- @transaction: ...` style comments) in a single migration file. Because the runner cannot decide which transaction mode to use, it refuses the script at parse time.","triggerScenarios":"Calling parseTransactionDirective (or the higher-level `directive` parser) on migration script text that contains multiple lines matching the transaction directive pattern, e.g. both `-- @transaction: none` and `-- @transaction: perStep`.","commonSituations":"Copy-pasting a header block from another migration that already carried a directive; merging migration files during a rebase; adding a new directive without removing the old commented one.","solutions":["Open the offending migration file and delete all but one transaction directive line.","If you intended different modes per section, split the migration into separate files since one file maps to one transaction mode.","Re-run the parse/registry load to confirm the file now yields a single mode."],"exampleFix":"// before\n-- @transaction: none\n-- @transaction: perStep\nCREATE TABLE ...\n\n// after\n-- @transaction: perStep\nCREATE TABLE ...","handlingStrategy":"validation","validationCode":"let directivePattern = /^\\s*--\\s*@transaction:\\s*(\\w+)/gm\ncount = (text.match(directivePattern) || []).length\nif (count > 1) throw new Error('multiple transaction directives: ' + count)","typeGuard":"function hasSingleTransactionDirective(text: string): boolean {\n  return (text.match(/^\\s*--\\s*@transaction:/gm) || []).length <= 1\n}","tryCatchPattern":"try {\n  let mode = parseTransactionDirective(script)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('more than one transaction directive')) {\n    // report file path and directive line numbers to the author\n  }\n  throw error\n}","preventionTips":["Generate migration files from a template containing exactly one directive line.","Lint migration files in CI for duplicate directive comments before they reach the runner."],"tags":["migrations","parse-error","duplicate-directive"],"backgroundTag":"duplicate-config-directive","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}