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

  1. Reformat the file with Prettier so JSX tags are well-formed and locations are stable, then rerun the codemod.
  2. Ensure the root element has both opening and closing tags (not a corrupted/self-closing root when inserting inside).
  3. Re-parse from a clean git state if the file was previously modified by another codemod.
  4. 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

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


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)