{"record":{"id":"8da831f7b0a03668","repo":"remotion-dev/remotion","slug":"cannot-interpolate-value-because-horizontal-t","errorCode":null,"errorMessage":"Cannot interpolate \"${value}\" because horizontal transform-origin keywords must come before a length-percentage value","messagePattern":"Cannot interpolate \"(.+?)\" because horizontal transform-origin keywords must come before a length-percentage value","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/interpolate.ts","lineNumber":329,"sourceCode":"\t\t\t? first\n\t\t\t: second.type === 'keyword'\n\t\t\t\t? second\n\t\t\t\t: null;\n\tconst length =\n\t\tfirst.type === 'length-percentage'\n\t\t\t? first.parsed\n\t\t\t: second.type === 'length-percentage'\n\t\t\t\t? second.parsed\n\t\t\t\t: null;\n\tif (keyword === null || length === null) {\n\t\tthrow new Error('Expected a keyword and a length-percentage value');\n\t}\n\n\tconst keywordIsFirst = first.type === 'keyword';\n\n\tif (keyword.keyword === 'left' || keyword.keyword === 'right') {\n\t\tif (!keywordIsFirst) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Cannot interpolate \"${value}\" because horizontal transform-origin keywords must come before a length-percentage value`,\n\t\t\t);\n\t\t}\n\n\t\treturn [transformOriginKeywordOptions(keyword.keyword)[0].value, length];\n\t}\n\n\tif (keyword.keyword === 'top' || keyword.keyword === 'bottom') {\n\t\treturn [length, transformOriginKeywordOptions(keyword.keyword)[0].value];\n\t}\n\n\treturn keywordIsFirst\n\t\t? [transformOriginCenter, length]\n\t\t: [length, transformOriginCenter];\n};\n\nconst parseTransformOriginValue = (\n\toutput: string,","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/interpolate.ts#L311-L347","documentation":"Thrown by parseTransformOriginXY when a horizontal keyword (left or right) is combined with a length-percentage value but the keyword comes second. Remotion requires horizontal keywords to precede the length value (\"left 50%\"), matching the canonical CSS authoring order it serializes. Placing the length first (\"50% left\") is rejected.","triggerScenarios":"A two-component transform-origin string of the form \"<length> left\" or \"<length> right\", e.g. \"50% left\", \"10px right\".","commonSituations":"Writing transform-origin values in a non-canonical order; mirroring vertical syntax (which does allow the length first) onto horizontal keywords.","solutions":["Put the horizontal keyword first: \"left 50%\" instead of \"50% left\".","Drop the keyword and use explicit percentages: \"0% 50%\" for left, \"100% 50%\" for right."],"exampleFix":"// before\ninterpolate(t, [0, 1], [\"50% left\", \"50% right\"]);\n// after\ninterpolate(t, [0, 1], [\"left 50%\", \"right 50%\"]);","handlingStrategy":"validation","validationCode":"function isCanonicalHorizontalKeywordPair(parts: string[]): boolean {\n  // Reject forms like \"50% left\" or \"10px right\"\n  if (parts.length !== 2) return true;\n  const [a, b] = parts.map((p) => p.toLowerCase());\n  const horizSecond = (a !== 'left' && a !== 'right') && (b === 'left' || b === 'right');\n  return !horizSecond;\n}\n\noutputRange.filter((s) => typeof s === 'string').forEach((s) => {\n  if (!isCanonicalHorizontalKeywordPair(s.trim().split(/\\s+/))) {\n    throw new Error('Horizontal keyword must precede the length value');\n  }\n});","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write horizontal keywords first: \"left 50%\", not \"50% left\".","Or skip keywords entirely and use \"0% 50%\" / \"100% 50%\"."],"tags":["interpolate","transform-origin","keywords","ordering","validation"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}