remotion-dev/remotion · error
Cannot update effect prop
Error message
Cannot update effect prop: ${found.reason} What it means
After locating the effects attribute, updateEffectPropsAst() calls findEffectCallExpression({attr, effectIndex}) to find the effect call at effectIndex. If that lookup fails (index out of range, entry not a call expression, etc.) it returns {kind: 'error', reason} and the library surfaces the reason in this templated error message. The actual reason is appended after 'Cannot update effect prop: '.
Solutions
- Re-enumerate the effects on the target element and re-map UI rows to fresh indices before updating.
- Clamp/validate effectIndex against the current number of call-expression effects.
- Refresh editor state after any reorder/delete/add codemod so indices stay in sync.
Example fix
// before
await updateEffectProps({input, effectIndex: staleIndex, sequenceNodePath, update, schema});
// after
const effects = listEffects(input, sequenceNodePath); // fresh enumeration
if (staleIndex >= effects.length) return;
await updateEffectProps({input, effectIndex: staleIndex, sequenceNodePath, update, schema}); Defensive patterns
Strategy: validation
Validate before calling
const effects = enumerateEffects(input, sequenceNodePath)
.filter((el) => el.kind === 'call');
if (effectIndex < 0 || effectIndex >= effects.length) {
throw new RangeError(`effectIndex ${effectIndex} out of range`);
} Type guard
const hasEffectAtIndex = (index: number, effects: EffectArrayElement[]) => Number.isInteger(index) && index >= 0 && index < effects.length && effects[index].kind === 'call';
Try / catch
try {
await updateEffectProps({input, effectIndex, sequenceNodePath, update, schema});
} catch (e) {
if (e instanceof Error && e.message.startsWith('Cannot update effect prop:')) {
// re-enumerate effects and rebind indices, then retry
} else throw e;
} Prevention
- Rebind UI rows to fresh indices after every add/delete/reorder codemod.
- Count only call-expression entries when assigning effectIndex.
When it happens
Trigger: Calling updateEffectProps with an effectIndex beyond the array length; effectIndex pointing at a spread/non-call element; index captured from a stale effect list after the file was edited (effects added/deleted/reordered).
Common situations: Property panel bound to an index that changed after a drag-reorder; concurrent edits to the source file invalidating indices; off-by-one when the panel counts effects including non-call entries.
Related errors
- Cannot reorder effect: target index not-found
- Cannot delete effect: no effects found
- Cannot reorder effect: source effect is not-call-expression
- Could not find as a reorder target
- A skill is already being installed or removed. Please try…
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/ac658d0ce4285d60.
Report an issue: GitHub.
Appendix: source
Thrown at packages/studio-codemods/src/effect-operations.ts:1035
serialized: string;
oldValueString: string;
newValueString: string;
logLine: number;
effectCallee: string;
removedProps: PropDelta[];
} => {
const ast = parseAst(input);
const snapshots = captureEffectSourceSnapshots(ast);
const jsx = getJsx({action: 'update', ast, sequenceNodePath});
trackOpeningElement({jsx, snapshots});
const attr = findEffectsAttr(jsx.attributes);
if (!attr) {
throw new Error('Could not find effects on the target JSX element');
}
const found = findEffectCallExpression({attr, effectIndex});
if (found.kind === 'error') {
throw new Error(`Cannot update effect prop: ${found.reason}`);
}
const {call, callee: effectCallee} = found;
const isDefault =
!isEffectParamUpdate(update) &&
update.defaultValue !== null &&
JSON.stringify(update.value) === JSON.stringify(update.defaultValue);
let object: ObjectExpression;
if (call.arguments.length === 0) {
if (isDefault) {
return {
serialized: input,
oldValueString: '',
newValueString: JSON.stringify(update.defaultValue),
logLine: call.loc?.start.line ?? jsx.loc?.start.line ?? 1,
effectCallee,
removedProps: [],
};View on GitHub (pinned to 46a3a6bf13)