remix-run/remix · error · TypeError

${message}

Error message

${message}

What it means

While serializing request transform invocations, each entry is normalized by normalizeAssetTransformInvocation; if an entry is malformed (unknown transform name, bad argument shape, etc.) the nested validator's message is re-thrown as a TypeError from serializeAssetTransformInvocations.

Source

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

    seen.add(normalizedExtension)
    normalizedExtensions.push(normalizedExtension)
  }

  return normalizedExtensions
}

export function serializeAssetTransformInvocations<transforms extends AssetRequestTransformMap>(
  transforms: readonly AssetTransformInvocation<transforms>[],
  transformsByName: ResolvedAssetRequestTransformMap,
  maxTransforms = defaultMaxRequestTransforms,
): string[] {
  if (transforms.length > maxTransforms) {
    throw new TypeError(`Expected at most ${maxTransforms} request transforms`)
  }

  return transforms.map((transformInvocation) =>
    normalizeAssetTransformInvocation(transformInvocation, transformsByName, (message) => {
      throw new TypeError(message)
    }),
  )
}

export function parseAssetTransformInvocations(
  transformsQuery: readonly string[],
  transformsByName: ResolvedAssetRequestTransformMap,
  maxTransforms = defaultMaxRequestTransforms,
): readonly (string | readonly [string, string])[] {
  if (transformsQuery.length > maxTransforms) {
    throw new TypeError(`Expected at most ${maxTransforms} request transforms`)
  }

  return transformsQuery.map((transformQuery) =>
    parseSerializedAssetTransformInvocation(transformQuery, transformsByName, (message) => {
      throw new TypeError(message)
    }),
  )

View on GitHub (pinned to 9696913134)

Solutions

  1. Check the exact nested message for the offending field and fix that entry
  2. Verify every invocation name exists in the resolved transforms map before serializing
  3. Regenerate/clear cached transform URLs after changing the transform registry

Example fix

// before
getHrefTransform([{ name: 'minifyy', args: [] }], map)
// after
getHrefTransform([{ name: 'minify', args: [] }], map)
Defensive patterns

Strategy: try-catch

Validate before calling

const valid = invocations.every((i) => i.name in transformsByName)
if (!valid) throw new Error('unknown transform name')

Type guard

function isKnownTransform(name: string, map: ResolvedAssetRequestTransformMap): boolean {
  return name in map
}

Try / catch

try { serializeAssetTransformInvocations(list, map) } catch (e) { if (e instanceof TypeError) logBadInvocation(e.message); throw e }

Prevention

When it happens

Trigger: Passing an invocation whose name is not in transformsByName, or whose args don't match the transform's declared argument types, to getHrefTransform/serializeAssetTransformInvocations.

Common situations: Renaming or removing a registered transform while stale references (cached URLs, old client bundles) still request it; typos in transform names; passing raw strings instead of invocation objects.

Understand the failure class

Background: Invalid option value errors: "must be one of", "is not a valid", and "only allows" failures explained — 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/5e8ecb44190d1901. Report an issue: GitHub.