remotion-dev/remotion · error

Cannot duplicate a JSX element without a source location

Error message

Cannot duplicate a JSX element without a source location

What it means

getDuplicatedJsxSource slices the original source text of the element to build the duplicated copy. If the JSXElement has no .loc, there is no source range to slice — the node isn't backed by source text — so duplication of source is impossible and it throws.

Solutions

  1. Reload the file in Studio so the AST is re-parsed from disk with fresh locations
  2. Ensure the target element exists as literal source text (not codegen) and retry the duplicate action
  3. Duplicate the JSX block manually

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

const nodeHasSource = (ast: any) => JSON.stringify(ast).includes('"loc":null') === false;

Type guard

const hasLoc = (n: {loc?: unknown}): n is {loc: NonNullable<unknown>} => n.loc != null;

Try / catch

try {
  await duplicateJsxNodes({input, nodePaths});
} catch (e) {
  if ((e as Error).message.includes('without a source location')) {
    // reload/reparse the file so nodes regain locations, then retry
  }
}

Prevention

When it happens

Trigger: duplicateJsxNodes (Studio duplicate-node action) resolves a node path to a JSX element whose loc is undefined — typically an element created by AST transformation rather than present in the original file.

Common situations: Duplicating a JSX node in a file that was previously generated/rewritten by codemods; stale Studio node paths pointing at synthesized nodes.

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/51a3cda30358b455. Report an issue: GitHub.

Appendix: source

Thrown at packages/studio-codemods/src/duplicate-jsx-node.ts:182

	const clone = cloneJsxElement(jsxNode);
	uniquifyNamePropOnClone(clone);

	if (insertDuplicateForParent(parentPath.node, jsxNode, clone)) {
		return;
	}

	jsxPath.replace(makeFragment(jsxNode, clone));
};

const getDuplicatedJsxSource = ({
	element,
	input,
}: {
	element: JSXElement;
	input: string;
}) => {
	if (!element.loc) {
		throw new Error('Cannot duplicate a JSX element without a source location');
	}

	const start = recastLocToOffset(input, element.loc.start);
	const end = recastLocToOffset(input, element.loc.end);
	let source = input.slice(start, end);
	const nameAttribute = element.openingElement.attributes.find(
		(attribute) =>
			attribute.type === 'JSXAttribute' &&
			attribute.name.type === 'JSXIdentifier' &&
			attribute.name.name === 'name' &&
			(attribute.value?.type === 'StringLiteral' ||
				(attribute.value?.type === 'JSXExpressionContainer' &&
					attribute.value.expression.type === 'StringLiteral')),
	);

	if (nameAttribute?.type === 'JSXAttribute') {
		const value =
			nameAttribute.value?.type === 'JSXExpressionContainer'

View on GitHub (pinned to 46a3a6bf13)