remix-run/remix · error · TypeError

${optionName} values must be package names. Received "${pack

Error message

${optionName} values must be package names. Received "${packageName}".

What it means

Execution-time backstop: any command reaching the migration loader (`migrate`, `rollback`, `status`, `reset`) must have `plan.migrations` set. It duplicates the plan-time check so a hand-built or partially populated plan cannot proceed with an undefined migrations directory. CLI users normally hit the plan-time variant instead.

Source

Thrown at packages/assets/src/lib/access.ts:151

      return inspect(filePath).allowed
    },
  }
}

function normalizePackageNames(
  packageOption: readonly string[] | undefined,
  optionName: 'allowPackages',
): Set<string> {
  let packageNames = new Set<string>()

  for (let packageName of packageOption ?? []) {
    if (typeof packageName !== 'string') {
      throw new TypeError(`${optionName} values must be strings`)
    }

    let normalizedPackageName = packageName.trim()
    if (!isValidPackageName(normalizedPackageName)) {
      throw new TypeError(`${optionName} values must be package names. Received "${packageName}".`)
    }

    packageNames.add(normalizedPackageName)
  }

  return packageNames
}

function validatePackageName(packageName: string, message: string): void {
  if (!isValidPackageName(packageName)) {
    throw new TypeError(message)
  }
}

type PackageJson = {
  dependencies?: Record<string, string>
  optionalDependencies?: Record<string, string>
}

View on GitHub (pinned to 9696913134)

Solutions

  1. Configure `db.migrations.directory` in remix.json or pass `--migrations`
  2. Always build plans through `resolveDatabaseCommandPlan`
  3. Validate the plan shape before executing

Example fix

// before
let plan = { command: 'migrate', db }
executeDatabaseCommand(plan)
// after
let plan = await resolveDatabaseCommandPlan(invocation, dbConfig)
executeDatabaseCommand(plan)
Defensive patterns

Strategy: try-catch

Validate before calling

if (plan.command !== 'seed' && plan.command !== 'wipe' && plan.migrations === undefined) {
  throw new Error('Plan is missing a migrations directory');
}

Type guard

function isMigrationPlan(plan: any): plan is { command: string; migrations: string } {
  return typeof plan.migrations === 'string';
}

Try / catch

Catch around executeDatabaseCommand; on 'requires db.migrations.directory' fix remix.json or retry with --migrations.

Prevention

When it happens

Trigger: Programmatically invoking `executeDatabaseCommand` with a plan for a migration command where `migrations === undefined`, skipping `resolveDatabaseCommandPlan`.

Common situations: Direct plan construction in scripts/tests; refactors that copy plans between commands and drop the migrations field.

Related errors


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