remix-run/remix · error · TypeError

files.extensions cannot include compiled asset extensions li

Error message

files.extensions cannot include compiled asset extensions like "${normalizedExtension}".

What it means

The asset server reserves compiled/built asset extensions (e.g. `.js`, `.css` output types) for its own pipeline. Listing one of them in `files.extensions` (which is for raw source files served as-is) would collide with compiled asset routing, so it is rejected.

Source

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

  }

  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')
  }

  let normalizedTransforms = new Map<
    string,
    AssetRequestTransform<string, AssetRequestTransformParamMode>
  >()

View on GitHub (pinned to 9696913134)

Solutions

  1. Remove the reserved compiled-asset extension from `files.extensions`
  2. If you need to transform those files, use `files.transforms` / `globalTransforms` which target compiled assets properly

Example fix

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

Strategy: validation

Validate before calling

const RESERVED = new Set(['.js', '.mjs', '.cjs', '.css']) // consult library's reserved set
let safe = extensions.filter((e) => !RESERVED.has(e))

Type guard

function isReservedExt(e: string, reserved: Set<string>): boolean {
  return reserved.has(e.trim().toLowerCase())
}

Prevention

When it happens

Trigger: Including a reserved extension such as `.js`, `.mjs`, `.css`, or similar compiled-output extension in `files.extensions`.

Common situations: Trying to serve raw `.js`/`.css` source files through the files pipeline instead of the transform pipeline; migrating configs that listed every extension the app uses, including build outputs.

Related errors


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