remotion-dev/remotion · error
Cannot duplicate effect
Error message
Cannot duplicate effect: ${found.reason} What it means
duplicateEffects validates each requested effect via findEffectCallExpression, which returns a discriminated result. When the result is an error ({kind:'error'}), the reason (e.g. 'not-found', 'out-of-range', 'not-call-expression') is interpolated into this message and thrown. It means the effectIndex does not resolve to a usable effect call in the element's effects array.
Solutions
- Re-read the element and enumerate its effects array to get fresh indexes before calling
- Verify effectIndex is within 0..effects.length-1 for the resolved element
- Remove or normalize non-CallExpression entries in the effects array
- Use the most recent effect listing (e.g. from the composition parse) as the index source
Example fix
// before
duplicateEffect({effectIndex: 3, ...}); // array has 2 entries
// after
const idx = effectsArray.length - 1; duplicateEffect({effectIndex: idx, ...}); Defensive patterns
Strategy: validation
Validate before calling
const el = findJsxElementAtNodePath(parseAst(input), sequenceNodePath);
const arr = getEffectsArray(findEffectsAttr(el!.openingElement.attributes)!, 'check');
if (effectIndex < 0 || effectIndex >= arr.elements.length) throw new Error('effectIndex out of range'); Type guard
const isValidEffectIndex = (n: number, len: number): boolean => Number.isInteger(n) && n >= 0 && n < len;
Try / catch
try { await duplicateEffect({effectIndex, input, sequenceNodePath}); } catch (e) { if ((e as Error).message.startsWith('Cannot duplicate effect:')) { /* refresh indices from a fresh parse and retry */ } else throw e; } Prevention
- Always derive effectIndex from a fresh parse of current source
- Invalidate cached indices when the file changes
- Keep effects arrays call-only to avoid ambiguous indices
When it happens
Trigger: duplicateEffects/duplicateEffect called with an effectIndex that does not exist in the element's effects array, indexes a non-call element (spread/conditional), or refers to a stale index after the array was modified.
Common situations: Stale effect indexes captured in Studio state before the file changed out-of-band; counting effects from a different element than the one the nodePath resolves to; effects array containing non-call entries.
Related errors
- Cannot reorder effect: source index not-found
- "colors" must be an array with at least 2 colors, but got
- "colors" must be an array with at least 2 colors, but got
- "colors" must be an array with at least 2 colors, but got
- "fieldOfView" must be <=
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/b13ec9180031ea3f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/studio-codemods/src/effect-operations.ts:487
JSXAttribute,
{
array: ArrayExpression;
indices: Set<number>;
effectLabels: string[];
logLines: number[];
}
>();
for (const {effectIndex, sequenceNodePath} of effects) {
const jsx = getJsx({action: 'duplicate', ast, sequenceNodePath});
const attr = findEffectsAttr(jsx.attributes);
if (!attr) {
throw new Error('Could not find effects on the target JSX element');
}
const array = getEffectsArray(attr, 'duplicate');
const found = findEffectCallExpression({attr, effectIndex});
if (found.kind === 'error') {
throw new Error(`Cannot duplicate effect: ${found.reason}`);
}
const group = effectsByAttribute.get(attr) ?? {
array,
indices: new Set<number>(),
effectLabels: [],
logLines: [],
};
effectsByAttribute.set(attr, group);
trackOpeningElement({jsx, snapshots});
if (group.indices.has(effectIndex)) {
continue;
}
group.indices.add(effectIndex);
group.effectLabels.push(`${found.callee}()`);
group.logLines.push(
found.call.loc?.start.line ?? jsx.loc?.start.line ?? 1,View on GitHub (pinned to 46a3a6bf13)