remix-run/remix · error · Error
Migration script declares more than one transaction directiv
Error message
Migration script declares more than one transaction directive
What it means
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.
Source
Thrown at packages/data-table/src/lib/migrations/directive.ts:31
*/
export function parseTransactionDirective(sql: string): MigrationTransactionMode | undefined {
let match: MigrationTransactionMode | undefined
for (let line of sql.split(/\r?\n/)) {
let trimmed = line.trim()
if (!trimmed.startsWith('--')) {
continue
}
let result = directivePattern.exec(trimmed)
if (!result) {
continue
}
if (match !== undefined) {
throw new Error('Migration script declares more than one transaction directive')
}
match = result[1].toLowerCase() as MigrationTransactionMode
}
return match
}
View on GitHub (pinned to 9696913134)
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.
Example fix
// before -- @transaction: none -- @transaction: perStep CREATE TABLE ... // after -- @transaction: perStep CREATE TABLE ...
Defensive patterns
Strategy: validation
Validate before calling
let directivePattern = /^\s*--\s*@transaction:\s*(\w+)/gm
count = (text.match(directivePattern) || []).length
if (count > 1) throw new Error('multiple transaction directives: ' + count) Type guard
function hasSingleTransactionDirective(text: string): boolean {
return (text.match(/^\s*--\s*@transaction:/gm) || []).length <= 1
} Try / catch
try {
let mode = parseTransactionDirective(script)
} catch (error) {
if (error instanceof Error && error.message.includes('more than one transaction directive')) {
// report file path and directive line numbers to the author
}
throw error
} Prevention
- 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.
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- expected promise to resolve, but it rejected with: ${stringi
- ${optionName} values must be package names. Received "${pack
- Cannot combine "to" and "step" migration options in the same
- Duplicate migration id "{id}" inferred from directory "{dire
- Migration directory "{directoryName}" is missing up.sql
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/65860d047c3471b4.
Report an issue: GitHub.