remotion-dev/remotion · error · Error
Could not locate the composition closing tag
Error message
Could not locate the composition closing tag
What it means
For insertInside insertions the codemod must find the composition root's closing tag (closingElement/closingFragment) to compute where children end. If the closing tag has no location and the root is not a self-closing JSX element with a locatable opening tag, it cannot compute the insertion offset and throws.
Solutions
- Reformat the file with Prettier so JSX tags are well-formed and locations are stable, then rerun the codemod.
- Ensure the root element has both opening and closing tags (not a corrupted/self-closing root when inserting inside).
- Re-parse from a clean git state if the file was previously modified by another codemod.
- If the root is self-closing, convert it to <tag></tag> form before inserting children.
Example fix
// before (self-closing root, insertInside) -> throws
<div />
// after
<div>
{/* children insert here */}
</div> Defensive patterns
Strategy: fallback
Validate before calling
const root = findCompositionRoot(parsed); const canInsertInside = Boolean(root && ((root.type === 'JSXFragment' && root.closingFragment?.loc) || (root.type === 'JSXElement' && (root.closingElement?.loc || root.openingElement?.loc)))); if (!canInsertInside) insertAsSiblingInstead();
Try / catch
try {
insertJsxElement({...opts, insertInside: true});
} catch (e) {
if (e instanceof Error && e.message === 'Could not locate the composition closing tag') {
prettierFormat(file); // stabilize JSX locations, then retry once
insertJsxElement({...opts, insertInside: true});
} else throw e;
} Prevention
- Run Prettier on files before applying JSX-inserting codemods
- Use explicit open/close tags on the composition root
- Re-parse from a clean state after other tooling rewrites the file
When it happens
Trigger: Calling the insert-JSX-element codemod with insertInside: true against a root whose closing tag is missing location info — typically malformed/recast-lost JSX, or a root that is neither a JSXElement with an openingElement.loc nor has closing tag locations.
Common situations: Files previously rewritten by tooling that dropped node locations; hand-minified JSX on one line missing loc data; parsing quirks where the closing element's source mapping is unavailable.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Cannot duplicate JSX element with no parent
- Cannot split a JSX sequence without a source location
- Cannot split JSX sequence with no parent
- Could not find a root JSX element
- Could not find a root JSX element
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/8e20367e1826faf3.
Report an issue: GitHub.
Appendix: source
Thrown at packages/studio-codemods/src/insert-jsx-element.ts:2296
insertion,
}),
`${nullIndent}${unit}</>`,
`${nullIndent})`,
].join(endOfLine),
start: nullStart,
};
}
if (!root?.loc) {
throw new Error('Could not locate the composition component root');
}
if (insertInside) {
const closing =
root.type === 'JSXFragment' ? root.closingFragment : root.closingElement;
if (!closing?.loc) {
if (root.type !== 'JSXElement' || !root.openingElement.loc) {
throw new Error('Could not locate the composition closing tag');
}
const openingStart = recastLocToOffset(
input,
root.openingElement.loc.start,
);
const openingEnd = recastLocToOffset(input, root.openingElement.loc.end);
const openingIndent = getLineIndent({input, offset: openingStart});
return {
start: openingStart,
end: openingEnd,
replacement: [
input.slice(openingStart, openingEnd).replace(/\s*\/>$/, '>'),
indentInsertedJsx({indent: `${openingIndent}${unit}`, insertion}),
`${openingIndent}</${recast.print(root.openingElement.name).code}>`,
].join(endOfLine),
};
}View on GitHub (pinned to 46a3a6bf13)