{"record":{"id":"b9d87c0fc7c267aa","repo":"remix-run/remix","slug":"expected-at-most-maxtransforms-request-transfor","errorCode":null,"errorMessage":"Expected at most ${maxTransforms} request transforms","messagePattern":"Expected at most (.+?) request transforms","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/files/config.ts","lineNumber":355,"sourceCode":"    if (!/^\\.[A-Za-z0-9_-]+$/.test(normalizedExtension)) {\n      throw new TypeError(`${optionPath} values must use \".ext\" format. Received \"${extension}\".`)\n    }\n\n    if (seen.has(normalizedExtension)) continue\n    seen.add(normalizedExtension)\n    normalizedExtensions.push(normalizedExtension)\n  }\n\n  return normalizedExtensions\n}\n\nexport function serializeAssetTransformInvocations<transforms extends AssetRequestTransformMap>(\n  transforms: readonly AssetTransformInvocation<transforms>[],\n  transformsByName: ResolvedAssetRequestTransformMap,\n  maxTransforms = defaultMaxRequestTransforms,\n): string[] {\n  if (transforms.length > maxTransforms) {\n    throw new TypeError(`Expected at most ${maxTransforms} request transforms`)\n  }\n\n  return transforms.map((transformInvocation) =>\n    normalizeAssetTransformInvocation(transformInvocation, transformsByName, (message) => {\n      throw new TypeError(message)\n    }),\n  )\n}\n\nexport function parseAssetTransformInvocations(\n  transformsQuery: readonly string[],\n  transformsByName: ResolvedAssetRequestTransformMap,\n  maxTransforms = defaultMaxRequestTransforms,\n): readonly (string | readonly [string, string])[] {\n  if (transformsQuery.length > maxTransforms) {\n    throw new TypeError(`Expected at most ${maxTransforms} request transforms`)\n  }\n","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/files/config.ts#L337-L373","documentation":"serializeAssetTransformInvocations enforces the maximum number of request transforms (default 16) that can be applied to a single asset request. It throws when the invocation list exceeds the configured cap, protecting URL length and transform-chain performance.","triggerScenarios":"Calling getHrefTransform (or serializeAssetTransformInvocations directly) with more than `maxTransforms` transform invocations, e.g. 17 entries when the cap is 16.","commonSituations":"Building transform chains dynamically (one per query param or per layer) that grow past 16; raising `files.maxRequestTransforms` in one place but not where serialization runs; browser extensions or middleware appending extra transforms.","solutions":["Raise the cap by passing a larger maxRequestTransforms consistently to both the server options and the serialization call","Filter/reduce the transform chain to only necessary transforms","If invoking serializeAssetTransformInvocations directly, pass an explicit maxTransforms argument"],"exampleFix":"// before\nserializeAssetTransformInvocations(invocations, map) // 17 invocations, default cap 16\n// after\nserializeAssetTransformInvocations(invocations, map, 32)","handlingStrategy":"validation","validationCode":"if (invocations.length > maxTransforms) {\n  invocations = invocations.slice(0, maxTransforms) // or raise the cap\n}","typeGuard":null,"tryCatchPattern":"try { serializeAssetTransformInvocations(list, map) } catch (e) { if (e instanceof TypeError && /request transforms/.test(e.message)) { /* trim chain or raise cap */ } throw e }","preventionTips":["Pass maxTransforms explicitly everywhere the cap applies","Cap transform chain length at URL-build time, not at serialization time"],"tags":["assets","transforms","limits","validation"],"backgroundTag":"limit-exceeded","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}