remix-run/remix · error · TypeError

files.extensions values must use ".ext" format. Received "${

Error message

files.extensions values must use ".ext" format. Received "${extension}".

What it means

After normalization (trim + lowercase), every `files.extensions` entry must match `.ext` — a leading dot followed only by letters, digits, underscores, or hyphens, with no additional dots or slashes. This error fires for malformed entries like `css`, `.tar.gz`, or `./css`.

Source

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

      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)) {
      throw new TypeError(
        `files.extensions cannot include compiled asset extensions like "${normalizedExtension}".`,
      )
    }

    if (seen.has(normalizedExtension)) continue
    seen.add(normalizedExtension)
    normalizedExtensions.push(normalizedExtension)
  }

  let transforms = files.transforms ?? {}
  if (transforms === null || typeof transforms !== 'object' || Array.isArray(transforms)) {
    throw new TypeError('files.transforms must be an object')

View on GitHub (pinned to 9696913134)

Solutions

  1. Format each entry as a single dotted extension: `['.css', '.md', '.tar']` (use only the final segment for multi-part extensions)
  2. Add the leading dot programmatically if needed: `ext.startsWith('.') ? ext : '.' + ext`
  3. Double the leading dot issue in env-var-derived lists

Example fix

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

Strategy: validation

Validate before calling

let extensions = raw.map((e: string) => (e.startsWith('.') ? e : '.' + e)).filter((e: string) => /^\.[A-Za-z0-9_-]+$/.test(e))

Type guard

function isDotExt(e: string): boolean {
  return /^\.[A-Za-z0-9_-]+$/.test(e.trim().toLowerCase())
}

Prevention

When it happens

Trigger: Passing `extensions: ['css']` (missing dot), `.tar.gz` (two segments), `.d.ts`, or entries containing path separators or whitespace that leaves invalid characters.

Common situations: Developers omitting the leading dot out of habit from other tools' extension lists; multi-part extensions; extensions with special characters like `!` or `+` which the regex rejects.

Related errors


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