{"record":{"id":"e74405d7bfc4ddcb","repo":"remotion-dev/remotion","slug":"cannot-split-audio-from-a-jsx-element-with-no-parent","errorCode":null,"errorMessage":"Cannot split audio from a JSX element with no parent","messagePattern":"Cannot split audio from a JSX element with no parent","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio-codemods/src/split-video-from-audio.ts","lineNumber":491,"sourceCode":"\t\t\t\t\treturn clone;\n\t\t\t\t}),\n\t\t\tselfClosing: true,\n\t\t},\n\t\tclosingElement: null,\n\t\tchildren: [],\n\t};\n\tconst audioSource = printInsertedJsx({\n\t\telement: audioElement as never,\n\t\tinput,\n\t\toriginalAttributeSources,\n\t\tprettierConfigOverride: formattingConfig,\n\t});\n\n\tsetBareMutedAttribute(jsxElement);\n\n\tconst {parentPath} = jsxPath;\n\tif (!parentPath) {\n\t\tthrow new Error('Cannot split audio from a JSX element with no parent');\n\t}\n\n\tconst insertedAfter = insertAfter(parentPath.node, jsxElement, audioElement);\n\tif (!insertedAfter) {\n\t\tjsxPath.replace(makeFragment(jsxElement, audioElement));\n\t}\n\n\tconst insertedAsJsxSibling =\n\t\tinsertedAfter &&\n\t\t(parentPath.node.type === 'JSXElement' ||\n\t\t\tparentPath.node.type === 'JSXFragment');\n\tconst output = applySourceEdits({\n\t\tinput,\n\t\tedits: [\n\t\t\t...getInsertImportSourceEdits({\n\t\t\t\tast,\n\t\t\t\tinput,\n\t\t\t\tprettierConfigOverride: formattingConfig,","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-codemods/src/split-video-from-audio.ts#L473-L509","documentation":"splitVideoFromAudio throws this when the target JSXElement's parentPath is null. To extract audio it must either insert the <Audio> sibling after the element in its parent, or wrap both in a fragment — neither is possible without a parent node. It indicates an AST invariant violation rather than a user-input problem.","triggerScenarios":"The resolved AST path for the JSX element has no parent, e.g. the element was treated as the program root, a synthetic detached node was passed, or path bookkeeping was broken before the parent lookup.","commonSituations":"Passing a node path whose node was removed/replaced in the AST, hand-constructed paths in custom tooling, or codemod bugs after prior in-place mutations invalidated the path.","solutions":["Obtain the element path from a fresh parseAst(input) call and use it before mutating the AST","Never mutate the AST between resolving the path and calling splitVideoFromAudio","Pass a nodePath from captureJsxNodePaths on the same input string","Report a bug if the Studio split action hits this on unmodified code"],"exampleFix":"// before (detached node)\nconst detachedPath = {node: someElement, parentPath: null};\nsplitVideoFromAudio({input, nodePath: detachedPath});\n// after (fresh, attached path)\nconst ast = parseAst(input);\nconst jsxPath = findJsxElementPathForDeletion(ast, nodePath);\nsplitVideoFromAudio({input, nodePath: jsxPath});","handlingStrategy":"try-catch","validationCode":"const ast = parseAst(input);\nconst jsxPath = findJsxElementPathForDeletion(ast, nodePath);\nif (!jsxPath || !jsxPath.parentPath) throw new Error('target element must be attached to a parent in the AST');","typeGuard":"const hasParent = (p: {parentPath: unknown}): p is {parentPath: NonNullable<typeof p.parentPath>} => p.parentPath != null;","tryCatchPattern":"try {\n  const result = await splitVideoFromAudio({input, nodePath});\n} catch (e) {\n  if (e instanceof Error && e.message.includes('no parent')) {\n    // resolve a fresh path from a fresh parse; detached paths cannot be repaired\n    const fresh = findJsxElementPathForDeletion(parseAst(input), nodePath);\n    return splitVideoFromAudio({input, nodePath: fresh});\n  }\n  throw e;\n}","preventionTips":["Never mutate or detach AST nodes before calling splitVideoFromAudio","Use paths returned by captureJsxNodePaths on the same input string","Don't pass hand-built path objects in custom tooling"],"tags":["ast","codemod","invariant"],"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"}