remotion-dev/remotion · error · Error

Could not locate the JSX element to move

Error message

Could not locate the JSX element to move

What it means

getJsxElementSourceForInsertion returns the original source string of a JSX element so it can be re-inserted elsewhere. It throws when the JSXElement AST node has no source location (element.loc is null), which makes it impossible to recover the element's text or its indentation.

Solutions

  1. Only pass JSXElements obtained from the recast-parsed original source; do not pass nodes you constructed yourself.
  2. If you cloned a node, preserve loc (or re-derive it) before calling, e.g. by keeping the original node reference.
  3. Re-parse the current source with recast so all nodes have loc, then locate the element again.
  4. Fall back to serializing the node with recast.print if you control the caller and loc cannot be restored.

Example fix

// before: passing a synthesized element
const text = getJsxElementSourceForInsertion({element: newElement, input});
// after: use the element found in the parsed tree
const parsed = parse(input).program.body[0]...;
const text = getJsxElementSourceForInsertion({element: parsedElement, input});
Defensive patterns

Strategy: type-guard

Validate before calling

if (!element.loc) {
  throw new Error('Element must come from a recast-parsed source tree');
}

Type guard

const isLocatable = <T extends {loc: unknown}>(node: T): node is T & {loc: NonNullable<T['loc']>} => node.loc != null;

Try / catch

try {
  const src = getJsxElementSourceForInsertion({element, input});
} catch (err) {
  // fall back to recast.print(element).code
}

Prevention

When it happens

Trigger: Calling this helper with a JSXElement that was created or cloned programmatically during the codemod (no loc), or with an element from a second parse that was not passed through recast's location-recording parser.

Common situations: Chained codemods where a transform builds a new JSXElement and another helper is expected to move it; cloning a node with {...node} without loc; parsing with a parser option that strips loc data.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18). Data as JSON: /api/errors/ec82335e39c9b148. Report an issue: GitHub.

Appendix: source

Thrown at packages/studio-codemods/src/source-edits.ts:68

					.replaceAll("'", '&apos;')
					.replaceAll('<', '&lt;') +
				quote
			: recast.prettyPrint(recast.types.builders.stringLiteral(newValue), {
					quote: quote === "'" ? 'single' : 'double',
				}).code;

	return {start, end, replacement};
};

export const getJsxElementSourceForInsertion = ({
	element,
	input,
}: {
	element: JSXElement;
	input: string;
}): string => {
	if (!element.loc) {
		throw new Error('Could not locate the JSX element to move');
	}

	const start = recastLocToOffset(input, element.loc.start);
	const end = recastLocToOffset(input, element.loc.end);
	const originalIndent = getLineIndent({input, offset: start});

	return input
		.slice(start, end)
		.split(/\r?\n/)
		.map((line, index) => {
			if (index === 0) {
				return line;
			}

			return line.startsWith(originalIndent)
				? line.slice(originalIndent.length)
				: line.trimStart();
		})

View on GitHub (pinned to 46a3a6bf13)