{"record":{"id":"526ba66378b58158","repo":"remix-run/remix","slug":"optionname-values-must-be-strings","errorCode":null,"errorMessage":"${optionName} values must be strings","messagePattern":"(.+?) values must be strings","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/access.ts","lineNumber":146,"sourceCode":"\n      packageRootsDirty = true\n    },\n    inspect,\n    isAllowed(filePath) {\n      return inspect(filePath).allowed\n    },\n  }\n}\n\nfunction normalizePackageNames(\n  packageOption: readonly string[] | undefined,\n  optionName: 'allowPackages',\n): Set<string> {\n  let packageNames = new Set<string>()\n\n  for (let packageName of packageOption ?? []) {\n    if (typeof packageName !== 'string') {\n      throw new TypeError(`${optionName} values must be strings`)\n    }\n\n    let normalizedPackageName = packageName.trim()\n    if (!isValidPackageName(normalizedPackageName)) {\n      throw new TypeError(`${optionName} values must be package names. Received \"${packageName}\".`)\n    }\n\n    packageNames.add(normalizedPackageName)\n  }\n\n  return packageNames\n}\n\nfunction validatePackageName(packageName: string, message: string): void {\n  if (!isValidPackageName(packageName)) {\n    throw new TypeError(message)\n  }\n}","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/access.ts#L128-L164","documentation":"Execution-time backstop in `executeDatabaseCommand`: before loading the seed module it re-checks `plan.seed`. Plans built through `resolveDatabaseCommandPlan` are already validated, so hitting this means a hand-constructed or mutated plan reached the executor — an internal invariant or programmatic misuse, not a CLI typo.","triggerScenarios":"Calling `executeDatabaseCommand`/`runDatabaseCommand` programmatically with a plan where `command === 'seed'` and `seed === undefined`, bypassing `resolveDatabaseCommandPlan`.","commonSituations":"Scripts or tests constructing plan objects by hand; refactors that drop or rename the seed field; partial plans copied between commands.","solutions":["Build plans via the planner (`resolveDatabaseCommandPlan`) instead of object literals","Set `db.seed` in remix.json or pass `--seed` so plans carry the field","Guard programmatically: `if (plan.command === 'seed' && !plan.seed) throw` before executing"],"exampleFix":"// before\nlet plan = { command: 'seed', db }\nexecuteDatabaseCommand(plan)\n// after\nlet plan = await resolveDatabaseCommandPlan(invocation, dbConfig)\nexecuteDatabaseCommand(plan)","handlingStrategy":"try-catch","validationCode":"if (plan.command === 'seed' && plan.seed === undefined) {\n  throw new Error('Seed plan requires a seed path');\n}","typeGuard":"function isExecutableSeedPlan(plan: any): plan is { command: 'seed'; seed: string } {\n  return plan.command === 'seed' && typeof plan.seed === 'string';\n}","tryCatchPattern":"Wrap executeDatabaseCommand in try/catch; on 'requires db.seed' surface guidance to set --seed or db.seed and rebuild the plan via the planner.","preventionTips":["Build plans via resolveDatabaseCommandPlan, never by hand","Assert required plan fields before execution"],"tags":["cli","database","seed","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}