remix-run/remix · error · TypeError

. is not a supported target

Error message

${optionPath}.${key} is not a supported target

What it means

Inside the script target object, only known target keys are allowed: `es` plus recognized browser target names (chrome, firefox, safari, etc.). An unrecognized key throws with the offending key name so typos don't silently drop targets.

Solutions

  1. Move ES version under the es key: { es: 2022 } instead of { es2022: true }
  2. Remove non-browser keys like node — they are not supported here
  3. Check the BrowserTargetName set in the docs/source for valid key names

Example fix

// before
script: { target: { es2020: true, node: 18 } }
// after
script: { target: { es: 2020, chrome: '100' } }
Defensive patterns

Strategy: validation

Validate before calling

const allowed = new Set(['es', 'chrome', 'firefox', 'safari', 'edge', 'ios', 'node' /* remove if unsupported */])
for (const key of Object.keys(target)) if (!allowed.has(key)) throw new Error('unsupported target: ' + key)

Type guard

function isSupportedTargetKey(key: string): boolean {
  return key === 'es' || browserTargetNameSet.has(key)
}

Prevention

When it happens

Trigger: Passing `{ target: { es2022: true } }`, `{ targt: ... }` typos, or non-browser keys like `{ node: 18 }` in script.target.

Common situations: Copy-pasting target config from esbuild (which accepts names like 'node' or version strings as keys); typos; using an outdated target name after a library update renamed it.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at packages/assets/src/lib/target.ts:106

function normalizeScriptTargetObject(
  target: AssetTarget | undefined,
  optionPath: string,
): NormalizedAssetTarget | undefined {
  if (target == null) return undefined
  if (!isPlainObject(target)) {
    throw new TypeError(`${optionPath} must be an object`)
  }

  let normalizedTarget: NormalizedAssetTarget = {}

  for (let [key, value] of Object.entries(target)) {
    if (key === 'es') {
      normalizedTarget.es = normalizeScriptTargetVersion(value, `${optionPath}.es`)
      continue
    }

    if (!browserTargetNameSet.has(key)) {
      throw new TypeError(`${optionPath}.${key} is not a supported target`)
    }

    normalizedTarget[key as BrowserTargetName] = normalizeBrowserTargetVersion(
      value,
      `${optionPath}.${key}`,
    )
  }

  return Object.keys(normalizedTarget).length === 0 ? undefined : normalizedTarget
}

function normalizeStyleTargetObject(
  target: AssetTarget | undefined,
  optionPath: string,
): NormalizedAssetTarget | undefined {
  if (target == null) return undefined
  if (!isPlainObject(target)) {
    throw new TypeError(`${optionPath} must be an object`)

View on GitHub (pinned to 9696913134)