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
- Pass the original source string as `input` so parseAst produces nodes with locations
- Avoid mutating/rebuilding the JSX AST before calling the effect operation
- 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
- Pass original source, never AST-only input
- Don't strip `loc` via parser options or node cloning
- Run effect operations on freshly parsed files
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
- Cannot duplicate effect: not-call-expression
- Cannot duplicate JSX element with no parent
- Cannot split a JSX sequence without a source location
- Cannot split JSX sequence with no parent
- Cannot update keyframes without a JSX source location
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)