{"record":{"id":"11da451105474b12","repo":"remotion-dev/remotion","slug":"could-not-find-a-root-jsx-element-folder-source-edits","errorCode":null,"errorMessage":"Could not find a root JSX element","messagePattern":"Could not find a root JSX element","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/studio-codemods/src/folder-source-edits.ts","lineNumber":143,"sourceCode":"\nconst getRegistrationRoot = (\n\tpath: recast.types.NodePath,\n): JSXElement | JSXFragment => {\n\tlet currentPath: recast.types.NodePath | null = path;\n\twhile (currentPath !== null) {\n\t\tconst node = currentPath.node as ReturnStatement;\n\t\tif (\n\t\t\tnode.type === 'ReturnStatement' &&\n\t\t\t(node.argument?.type === 'JSXElement' ||\n\t\t\t\tnode.argument?.type === 'JSXFragment')\n\t\t) {\n\t\t\treturn node.argument;\n\t\t}\n\n\t\tcurrentPath = currentPath.parentPath ?? null;\n\t}\n\n\tthrow new Error('Could not find a root JSX element');\n};\n\nconst getNewFolderSourceEdits = ({\n\tast,\n\tinput,\n}: {\n\tast: File;\n\tinput: string;\n}): SourceEdit[] => {\n\tconst snapshots = captureImportSnapshots(ast);\n\tconst localName = ensureNamedImport({\n\t\tast,\n\t\timportedName: 'Folder',\n\t\tsourcePath: 'remotion',\n\t\tlocalName: 'Folder',\n\t});\n\tlet insertionEdit: SourceEdit | null = null;\n","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-codemods/src/folder-source-edits.ts#L125-L161","documentation":"Thrown by getRegistrationRoot in packages/studio-codemods/src/folder-source-edits.ts:143 when walking up the AST from a JSX element finds no `return <JSXElement|JSXFragment>` statement. Remotion Studio codemods assume compositions/folders live inside a JSX tree returned from a Root component; when the moving element's enclosing function has no returned JSX root, the codemod cannot know where to re-insert the element and aborts.","triggerScenarios":"Executing a `move-composition-to-folder` codemod with `folderName: null` (move to root) whose source element is not lexically nested under a `return <Root>...</Root>` expression — e.g. the composition JSX is built in a variable, returned conditionally, or generated programmatically.","commonSituations":"A Root file that assembles the compositions tree dynamically (array.map into a variable, ternary returns, multiple return statements without a JSX argument, or a default export that is not a component returning JSX). Moving a composition back to the root level via Remotion Studio drag & drop then fails.","solutions":["Restructure the Root file so the compositions/folders are statically written inside a single `return (<Root>...</Root>)` JSX expression","Move the target composition element out of any helper function or variable into the main returned JSX tree","If the file must build JSX dynamically, perform the move manually in the editor instead of via the Studio codemod"],"exampleFix":"// before\nconst tree = <Root>\n  <Composition id=\"MyComp\" ... />\n</Root>;\nexport const RemotionRoot = () => tree;\n\n// after\nexport const RemotionRoot = () => {\n  return (\n    <Root>\n      <Composition id=\"MyComp\" ... />\n    </Root>\n  );\n};","handlingStrategy":"validation","validationCode":"const hasJsxReturnRoot = (source: string) => /return\\s*\\(?\\s*<(Root|[A-Z][\\w.]*)/.test(source);\nif (!hasJsxReturnRoot(rootFileSource)) {\n  throw new Error('Root file must return a literal JSX tree for Studio codemods');\n}","typeGuard":"const isJsxRootReturn = (n: {type: string; argument?: {type: string} | null}): n is {type: 'ReturnStatement'; argument: {type: 'JSXElement' | 'JSXFragment'}} =>\n  n.type === 'ReturnStatement' && (n.argument?.type === 'JSXElement' || n.argument?.type === 'JSXFragment');","tryCatchPattern":"try {\n  editFolderInSource({codeMod, input});\n} catch (e) {\n  if (e instanceof Error && e.message === 'Could not find a root JSX element') {\n    // fall back to manual edit / surface a user-facing hint\n  }\n}","preventionTips":["Keep the compositions tree as a single static `return (<Root>...</Root>)` expression","Avoid building the tree in variables or helper functions","Don't refactor Root files with code transforms that strip JSX literals"],"tags":["ast","codemod","jsx","remotion-studio"],"backgroundTag":"internal-invariant-violation","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}