{"record":{"id":"7857b5ee0bcf89a9","repo":"remix-run/remix","slug":"invalid-migration-step-option-expected-a-positive","errorCode":null,"errorMessage":"Invalid migration step option. Expected a positive integer.","messagePattern":"Invalid migration step option\\. Expected a positive integer\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/data-table/src/lib/migrations/runner.ts","lineNumber":52,"sourceCode":"import { resolveMigrations } from './registry.ts'\n\ntype MigrationRunnerContext = DatabaseDriver\n\ntype RunMigrationsInput = {\n  driver: MigrationRunnerContext\n  migrations: MigrationDescriptor[]\n  journalTable: string\n  direction: MigrationDirection\n  options: MigrationOperationOptions\n}\n\nfunction assertStepOption(step: number | undefined): void {\n  if (step === undefined) {\n    return\n  }\n\n  if (!Number.isInteger(step) || step < 1) {\n    throw new Error('Invalid migration step option. Expected a positive integer.')\n  }\n}\n\nfunction assertMigrationOperationOptions(options: MigrationOperationOptions): void {\n  if (options.to !== undefined && options.step !== undefined) {\n    throw new Error('Cannot combine \"to\" and \"step\" migration options in the same run')\n  }\n}\n\nfunction resolveTargetOption(\n  migrations: MigrationDescriptor[],\n  to: string | undefined,\n): string | undefined {\n  if (to === undefined) {\n    return undefined\n  }\n\n  // Accept either a bare migration id or the full `id_name` directory form and","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table/src/lib/migrations/runner.ts#L34-L70","documentation":"The `step` option passed to the migration runner was defined but not a positive integer. Steps control how many migrations to apply/rollback, so fractional, zero, negative, or non-integer values are rejected before any work runs.","triggerScenarios":"Calling runMigrations with `{ step: 0 }`, `{ step: -1 }`, `{ step: 1.5 }`, or `{ step: '2' }` (string from CLI/env not coerced). assertStepOption is invoked by runMigrationsUnlocked.","commonSituations":"Passing a raw CLI argument or environment variable straight into options without parsing; computing step as a difference that can be 0 or negative.","solutions":["Pass a positive integer: `step: 2` for two migrations, or omit `step` entirely.","Coerce CLI/env inputs with `Number.parseInt(value, 10)` and validate before calling run.","Use `1` for single-step rollbacks instead of `0` or `-1`."],"exampleFix":"// before\nawait runMigrations(db, { direction: 'down', step: Number(argv[2]) })\n\n// after\nawait runMigrations(db, { direction: 'down', step: Math.max(1, Number.parseInt(argv[2], 10) || 1) })","handlingStrategy":"type-guard","validationCode":"if (step !== undefined && (!Number.isInteger(step) || step < 1)) {\n  throw new Error('--step must be a positive integer')\n}","typeGuard":"function isValidStep(step: unknown): step is number {\n  return typeof step === 'number' && Number.isInteger(step) && step >= 1\n}","tryCatchPattern":null,"preventionTips":["Parse and validate CLI args before passing them into migration options.","Clamp computed step values to at least 1."],"tags":["migrations","options-validation","cli"],"backgroundTag":"invalid-option-value","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}