remix-run/remix · error · UsageError

Options --step and --to are mutually exclusive

Error message

Options --step and --to are mutually exclusive

What it means

For remix db migrate, the --step (migrate N steps) and --to (migrate up to a specific migration) options select the migration endpoint and cannot be combined; passing both is rejected.

Source

Thrown at packages/cli/src/lib/commands/db.ts:150

    return { command, ...parsed.options }
  }

  if (command === 'rollback') {
    let parsed = parseArgs(
      commandArgv,
      {
        connectionEnv: connectionOption,
        dryRun: { flag: '--dry-run', type: 'boolean' },
        journalTable: journalOption,
        migrations: migrationsOption,
        step: { flag: '--step', type: 'string' },
        to: { flag: '--to', type: 'string' },
      },
      { maxPositionals: 0 },
    )

    if (parsed.options.step !== undefined && parsed.options.to !== undefined) {
      throw invalidOptionValue('Options --step and --to are mutually exclusive')
    }

    let { step: rawStep, ...options } = parsed.options
    return { command, ...options, step: parseStepOption(rawStep) }
  }

  if (command === 'reset') {
    let parsed = parseArgs(
      commandArgv,
      {
        connectionEnv: connectionOption,
        force: { flag: '--force', type: 'boolean' },
        journalTable: journalOption,
        migrations: migrationsOption,
        seed: seedOption,
      },
      { maxPositionals: 0 },
    )

View on GitHub (pinned to 9696913134)

Solutions

  1. Keep only one endpoint option: either --step N or --to <migration-id>
  2. Drop the irrelevant flag from scripts/CI invocations
  3. Re-read remix db migrate --help to pick the right selector for the goal

Example fix

# before
$ remix db migrate --step 2 --to 0003_add_users

# after
$ remix db migrate --to 0003_add_users
Defensive patterns

Strategy: validation

Validate before calling

function validMigrateOptions(argv: string[]): boolean {
  return !(argv.includes('--step') || argv.some((a) => a.startsWith('--step=')) &&
           argv.includes('--to') || argv.some((a) => a.startsWith('--to=')))
}

Try / catch

try {
  runDbCommand(['migrate', ...flags], context)
} catch (error) {
  if (/mutually exclusive/.test(error.message)) failFast('pick --step or --to, not both')
  else throw error
}

Prevention

When it happens

Trigger: parseDbCommandArgs for the migrate branch finds both parsed.options.step and parsed.options.to defined, e.g. remix db migrate --step 2 --to 0003_add_users.

Common situations: Copy-pasting flags from history; scripts that always pass --to and add --step conditionally; misunderstanding that the two are alternative endpoint selectors.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/b3c9249859c6cbd0. Report an issue: GitHub.