{"record":{"id":"c8baa218c0afac0b","repo":"remix-run/remix","slug":"optionpath-must-be-an-array","errorCode":null,"errorMessage":"${optionPath} must be an array","messagePattern":"(.+?) must be an array","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/files/config.ts","lineNumber":322,"sourceCode":"  }\n\n  return {\n    cache: files.cache,\n    extensions: normalizedExtensions,\n    globalTransforms: normalizedGlobalTransforms,\n    hasTransforms: normalizedTransforms.size > 0 || normalizedGlobalTransforms.length > 0,\n    maxRequestTransforms,\n    transforms: normalizedTransforms,\n  }\n}\n\nfunction normalizeTransformExtensions(\n  extensions: readonly string[] | undefined,\n  optionPath: string,\n): readonly string[] | undefined {\n  if (extensions === undefined) return undefined\n  if (!Array.isArray(extensions)) {\n    throw new TypeError(`${optionPath} must be an array`)\n  }\n  if (extensions.length === 0) {\n    throw new TypeError(`${optionPath} must include at least one extension`)\n  }\n\n  let normalizedExtensions: string[] = []\n  let seen = new Set<string>()\n\n  for (let extension of extensions) {\n    if (typeof extension !== 'string') {\n      throw new TypeError(`${optionPath} values must be strings`)\n    }\n\n    let normalizedExtension = extension.trim().toLowerCase()\n    if (!/^\\.[A-Za-z0-9_-]+$/.test(normalizedExtension)) {\n      throw new TypeError(`${optionPath} values must use \".ext\" format. Received \"${extension}\".`)\n    }\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/files/config.ts#L304-L340","documentation":"Options like `files.transformExtensions` (and sibling extension lists) must be arrays of strings when provided. normalizeTransformExtensions rejects any non-array value with a TypeError naming the exact option path.","triggerScenarios":"Passing `files: { transformExtensions: '.css' }` (a string instead of an array), a Set, or a comma-joined string like '.css,.js' to resolveAssetServerOptions.","commonSituations":"Reading extensions from an env var or CLI arg, which yields a string; spreading a possibly-undefined value; or assuming a single extension can be passed as a bare string.","solutions":["Wrap the value in an array: ['.css']","When parsing from env/CLI, split on commas and filter empties","Leave the option undefined to accept the default extension set"],"exampleFix":"// before\nfiles: { transformExtensions: '.css' }\n// after\nfiles: { transformExtensions: ['.css'] }","handlingStrategy":"validation","validationCode":"if (ext !== undefined && !Array.isArray(ext)) throw new Error('transformExtensions must be an array')","typeGuard":"function isStringArray(v: unknown): v is readonly string[] {\n  return Array.isArray(v) && v.every((e) => typeof e === 'string')\n}","tryCatchPattern":null,"preventionTips":["Split env-var strings on ',' before passing","Type config fields as readonly string[] so TS flags strings"],"tags":["config","validation","assets"],"backgroundTag":"invalid-option-value","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}