remotion-dev/remotion · error

Cannot update effect without a JSX source location

Error message

Cannot update effect without a JSX source location

What it means

getEffectSourceOutput rewrites opening JSX elements that were modified (new/changed `effects` prop) by replacing the original source text at the recorded location. Each tracked opening element must have a source location; if a snapshot's location is null the codemod cannot compute the text range to patch and throws. It is an invariant guard protecting the edit pipeline used by addEffect, duplicateEffects, reorderEffect, deleteEffects, pasteEffects and updateEffectPropsAst.

Solutions

  1. Pass the original source string as `input` so parseAst produces nodes with locations
  2. Avoid mutating/rebuilding the JSX AST before calling the effect operation
  3. Verify `jsx.loc` / openingElement.loc is non-null before invoking; skip or re-parse otherwise

Example fix

// before
const ast = parse(input, {loc: false}); addEffect({input, ...})
// after
addEffect({input: originalSource, ...}) // parsed internally with locations
Defensive patterns

Strategy: validation

Validate before calling

for (const el of allOpeningElements(ast)) {
  if (!el.loc) throw new Error('opening element missing source location; re-parse original source');
}

Type guard

const located = (el: JSXOpeningElement | null | undefined): el is JSXOpeningElement & {loc: SourceLocation} => !!el?.loc;

Try / catch

try { await addEffect({...}); } catch (e) { if ((e as Error).message.includes('without a JSX source location')) { /* re-run with the pristine source string */ } else throw e; }

Prevention

When it happens

Trigger: Any effect operation (addEffect, duplicateEffects, reorderEffect, deleteEffects, pasteEffects, updateEffectPropsAst) on input whose JSX opening elements lack `loc` — e.g. the AST was parsed without locations or the opening element node was synthesized without positions.

Common situations: Passing machine-generated JSX source into effect operations; parsing with a parser configuration that strips location data; an AST that was transformed by other tooling before captureEffectSourceSnapshots.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — 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/cc8c5c0fe018da32. Report an issue: GitHub.

Appendix: source

Thrown at packages/studio-codemods/src/effect-operations.ts:228

				const blockStart = recastLocToOffset(input, body.loc.start);
				const blockEnd = recastLocToOffset(input, body.loc.end);
				return (
					blockStart < offset &&
					offset < blockEnd &&
					input.lastIndexOf('\n', blockStart - 1) + 1 === lineStart
				);
			},
		);
		const lineIndent = getLineIndent({input, offset});
		return startsInsideSameLineFunctionBlock
			? `${lineIndent}${getIndentationUnit(input, prettierConfigOverride)}`
			: lineIndent;
	};

	const openingElementEdits: SourceEdit[] = [];
	for (const [openingElement, location] of snapshots.openingElementLocations) {
		if (!location) {
			throw new Error('Cannot update effect without a JSX source location');
		}

		const start = recastLocToOffset(input, location.start);
		const end = recastLocToOffset(input, location.end);
		if (isCoveredByFunctionEdit(start, end)) {
			continue;
		}

		const original = input.slice(start, end);
		if (recast.print(openingElement).code === original) {
			continue;
		}

		const replacement = indentContinuationLines({
			indent: getJsxSourceIndent(start),
			input,
			printed: printJsxOpeningElement({
				openingElement: openingElement as never,

View on GitHub (pinned to 46a3a6bf13)