{"record":{"id":"732ee3e363a202ca","repo":"remotion-dev/remotion","slug":"cannot-interpolate-value-because-component-732ee3","errorCode":null,"errorMessage":"Cannot interpolate \"${value}\" because \"${component}\" is not a supported transform-origin ${allowPercentage ? 'length-percentage' : 'z length'}","messagePattern":"Cannot interpolate \"(.+?)\" because \"(.+?)\" is not a supported transform-origin (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/interpolate.ts","lineNumber":186,"sourceCode":"\t}\n\n\tthrow new TypeError(\n\t\t`Cannot interpolate \"${value}\" because \"${unit}\" is not a supported translate or rotate unit`,\n\t);\n};\n\nconst parseTransformOriginLengthPercentage = ({\n\tcomponent,\n\tvalue,\n\tallowPercentage,\n}: {\n\tcomponent: string;\n\tvalue: string;\n\tallowPercentage: boolean;\n}): TransformOriginAxisValue => {\n\tconst match = cssNumberRegex.exec(component);\n\tif (match === null) {\n\t\tthrow new TypeError(\n\t\t\t`Cannot interpolate \"${value}\" because \"${component}\" is not a supported transform-origin ${allowPercentage ? 'length-percentage' : 'z length'}`,\n\t\t);\n\t}\n\n\tconst unit = match[2] ?? null;\n\tconst numberValue = Number(match[1]);\n\tif (!Number.isFinite(numberValue)) {\n\t\tthrow new TypeError(\n\t\t\t`Cannot interpolate \"${value}\" because \"${component}\" is not finite`,\n\t\t);\n\t}\n\n\tif (\n\t\tunit === null ||\n\t\t!lengthUnits.has(unit) ||\n\t\t(!allowPercentage && unit === '%')\n\t) {\n\t\tthrow new TypeError(","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/interpolate.ts#L168-L204","documentation":"Thrown by parseTransformOriginLengthPercentage when a transform-origin component (the x/y slot, or the z slot) does not match the CSS number regex /^([+-]?(?:\\d+\\.?\\d*|\\.\\d+))([a-zA-Z%]+)?$/. Remotion's interpolate() accepts CSS transform-origin strings only when each non-keyword component is a number optionally followed by a unit. The message distinguishes the length-percentage axes (x/y) from the z-length axis via the allowPercentage flag.","triggerScenarios":"Call interpolate(input, inputRange, outputRange) where an outputRange string contains a transform-origin keyword (left/right/top/bottom/center) so it is routed to parseTransformOriginValue, AND a sibling component is not parseable as a number+unit. Examples: \"left xyz\" (xyz fails the regex on the x/y axis), \"top #ff0000\", \"center center bogus\" (bogus fails on the z axis).","commonSituations":"Passing color strings, CSS functions like calc(...) or var(...), comma-separated values, or typos such as \"lef\" into a transform-origin slot. Also using a keyword plus a non-numeric token (e.g. \"center auto\").","solutions":["Replace the offending component with a number plus a length unit, e.g. \"left 50%\" or \"center 10px\".","If you intended a non-numeric value (e.g. a color), use a numeric/tuple outputRange instead of a transform-origin string.","Keep the z component (third part) a pure length (no %): \"center center 20px\"."],"exampleFix":"// before\ninterpolate(t, [0, 1], [\"left bad\", \"right 50%\"]);\n// after\ninterpolate(t, [0, 1], [\"left 0%\", \"right 50%\"]);","handlingStrategy":"validation","validationCode":"const cssNumberRegex = /^([+-]?(?:\\d+\\.?\\d*|\\.\\d+))([a-zA-Z%]+)?$/;\nconst transformOriginKeywords = new Set(['left','center','right','top','bottom']);\n\nfunction isValidTransformOriginComponent(part: string, allowPercentage: boolean): boolean {\n  if (transformOriginKeywords.has(part.toLowerCase())) return true;\n  const m = cssNumberRegex.exec(part);\n  if (!m) return false;\n  if (!Number.isFinite(Number(m[1]))) return false;\n  const unit = m[2] ?? null;\n  if (unit === null) return false;\n  if (!allowPercentage && unit === '%') return false;\n  return true;\n}\n\n// before calling interpolate, validate each transform-origin string:\nconst parts = output.trim().split(/\\s+/);\nconst ok = parts.length >= 1 && parts.length <= 3\n  && parts.every((p, i) => isValidTransformOriginComponent(p, i < 2));","typeGuard":"function isTransformOriginString(value: string): boolean {\n  try {\n    const parts = value.trim().split(/\\s+/);\n    if (parts.length < 1 || parts.length > 3) return false;\n    if (!parts.every((p) => /^([+-]?(?:\\d+\\.?\\d*|\\.\\d+))([a-zA-Z%]+)?$/.test(p)\n        || /^(left|center|right|top|bottom)$/i.test(p))) return false;\n    return true;\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":null,"preventionTips":["Always pair transform-origin keywords with a number plus a length unit (%, px, em, etc.).","Reserve the third (z) component for a non-% length.","Run a quick regex check on author-facing strings before passing them to interpolate()."],"tags":["interpolate","transform-origin","string-interpolation","validation"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}