remix-run/remix · error · TypeError

files.extensions must be an array

Error message

files.extensions must be an array

What it means

When a `files` config object is provided to the asset server, its `extensions` field must be an array of file-extension strings. This error fires when `files.extensions` exists but is not an array (string, object, number, etc.).

Source

Thrown at packages/assets/src/lib/files/config.ts:184

const reservedFileExtensions = new Set<string>([...supportedScriptExtensions, '.css', '.map'])
const defaultMaxRequestTransforms = 5

export function normalizeFilesOptions<transforms extends AssetRequestTransformMap>(
  files: AssetServerFilesOptions<transforms> | undefined,
): ResolvedAssetServerFilesOptions {
  if (files == null) {
    return {
      extensions: [],
      globalTransforms: [],
      hasTransforms: false,
      maxRequestTransforms: defaultMaxRequestTransforms,
      transforms: new Map(),
    }
  }

  if (!Array.isArray(files.extensions)) {
    throw new TypeError('files.extensions must be an array')
  }

  let normalizedExtensions: string[] = []
  let seen = new Set<string>()

  for (let extension of files.extensions) {
    if (typeof extension !== 'string') {
      throw new TypeError('files.extensions values must be strings')
    }

    let normalizedExtension = extension.trim().toLowerCase()
    if (!/^\.[A-Za-z0-9_-]+$/.test(normalizedExtension)) {
      throw new TypeError(
        `files.extensions values must use ".ext" format. Received "${extension}".`,
      )
    }

    if (reservedFileExtensions.has(normalizedExtension)) {

View on GitHub (pinned to 9696913134)

Solutions

  1. Wrap the value in an array: `extensions: ['.css', '.md']`
  2. If you don't want to override the defaults, omit `files.extensions` entirely
  3. Split comma-separated strings before passing: `extensions: raw.split(',')`

Example fix

// before
files: { extensions: '.css' }
// after
files: { extensions: ['.css'] }
Defensive patterns

Strategy: type-guard

Validate before calling

if (filesConfig.extensions !== undefined && !Array.isArray(filesConfig.extensions)) {
  throw new Error('files.extensions must be an array of strings')
}

Type guard

function isExtensionArray(v: unknown): v is string[] {
  return Array.isArray(v) && v.every((e) => typeof e === 'string')
}

Prevention

When it happens

Trigger: Passing `files: { extensions: '.css' }` (a single string) or a non-array value like an object map of extensions.

Common situations: Copy-pasting a glob string or comma-separated list ('.css,.md') into `extensions`; config schemas from other tools (esbuild `loader` maps) pasted wholesale; YAML parsing a single item into a scalar instead of a list.

Related errors


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