{"record":{"id":"ac658d0ce4285d60","repo":"remotion-dev/remotion","slug":"cannot-update-effect-prop-found-reason","errorCode":null,"errorMessage":"Cannot update effect prop: ${found.reason}","messagePattern":"Cannot update effect prop: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/studio-codemods/src/effect-operations.ts","lineNumber":1035,"sourceCode":"\tserialized: string;\n\toldValueString: string;\n\tnewValueString: string;\n\tlogLine: number;\n\teffectCallee: string;\n\tremovedProps: PropDelta[];\n} => {\n\tconst ast = parseAst(input);\n\tconst snapshots = captureEffectSourceSnapshots(ast);\n\tconst jsx = getJsx({action: 'update', ast, sequenceNodePath});\n\ttrackOpeningElement({jsx, snapshots});\n\tconst attr = findEffectsAttr(jsx.attributes);\n\tif (!attr) {\n\t\tthrow new Error('Could not find effects on the target JSX element');\n\t}\n\n\tconst found = findEffectCallExpression({attr, effectIndex});\n\tif (found.kind === 'error') {\n\t\tthrow new Error(`Cannot update effect prop: ${found.reason}`);\n\t}\n\n\tconst {call, callee: effectCallee} = found;\n\tconst isDefault =\n\t\t!isEffectParamUpdate(update) &&\n\t\tupdate.defaultValue !== null &&\n\t\tJSON.stringify(update.value) === JSON.stringify(update.defaultValue);\n\tlet object: ObjectExpression;\n\tif (call.arguments.length === 0) {\n\t\tif (isDefault) {\n\t\t\treturn {\n\t\t\t\tserialized: input,\n\t\t\t\toldValueString: '',\n\t\t\t\tnewValueString: JSON.stringify(update.defaultValue),\n\t\t\t\tlogLine: call.loc?.start.line ?? jsx.loc?.start.line ?? 1,\n\t\t\t\teffectCallee,\n\t\t\t\tremovedProps: [],\n\t\t\t};","sourceCodeStart":1017,"sourceCodeEnd":1053,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-codemods/src/effect-operations.ts#L1017-L1053","documentation":"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: '.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nawait updateEffectProps({input, effectIndex: staleIndex, sequenceNodePath, update, schema});\n// after\nconst effects = listEffects(input, sequenceNodePath); // fresh enumeration\nif (staleIndex >= effects.length) return;\nawait updateEffectProps({input, effectIndex: staleIndex, sequenceNodePath, update, schema});","handlingStrategy":"validation","validationCode":"const effects = enumerateEffects(input, sequenceNodePath)\n  .filter((el) => el.kind === 'call');\nif (effectIndex < 0 || effectIndex >= effects.length) {\n  throw new RangeError(`effectIndex ${effectIndex} out of range`);\n}","typeGuard":"const hasEffectAtIndex = (index: number, effects: EffectArrayElement[]) =>\n  Number.isInteger(index) && index >= 0 && index < effects.length && effects[index].kind === 'call';","tryCatchPattern":"try {\n  await updateEffectProps({input, effectIndex, sequenceNodePath, update, schema});\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Cannot update effect prop:')) {\n    // re-enumerate effects and rebind indices, then retry\n  } else throw e;\n}","preventionTips":["Rebind UI rows to fresh indices after every add/delete/reorder codemod.","Count only call-expression entries when assigning effectIndex."],"tags":["index-out-of-range","ast","studio"],"backgroundTag":"index-out-of-bounds","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}