{"record":{"id":"5dd822dd7dd61613","repo":"remotion-dev/remotion","slug":"no-effects-were-specified-for-deletion-effect-operations","errorCode":null,"errorMessage":"No effects were specified for deletion","messagePattern":"No effects were specified for deletion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/studio-codemods/src/effect-operations.ts","lineNumber":644,"sourceCode":"\t\t};\n\t});\n\nexport const deleteEffects = ({\n\teffects,\n\tinput,\n\tprettierConfigOverride,\n}: {\n\teffects: EffectDeletionTarget[];\n\tinput: string;\n} & EffectSourceStyleOptions): Promise<{\n\toutput: string;\n\tformatted: boolean;\n\teffectLabels: string[];\n\tlogLines: number[];\n}> =>\n\tPromise.resolve().then(() => {\n\t\tif (effects.length === 0) {\n\t\t\tthrow new Error('No effects were specified for deletion');\n\t\t}\n\n\t\tconst ast = parseAst(input);\n\t\tconst snapshots = captureEffectSourceSnapshots(ast);\n\t\tconst effectsByAttribute = new Map<\n\t\t\tJSXAttribute,\n\t\t\t{\n\t\t\t\tall: boolean;\n\t\t\t\tarray: ArrayExpression;\n\t\t\t\tattributes: JSXOpeningElement['attributes'];\n\t\t\t\tindices: Set<number>;\n\t\t\t\teffectLabels: string[];\n\t\t\t\tlogLines: number[];\n\t\t\t}\n\t\t>();\n\t\tfor (const effect of effects) {\n\t\t\tconst jsx = getJsx({\n\t\t\t\taction: 'delete',","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio-codemods/src/effect-operations.ts#L626-L662","documentation":"deleteEffects() takes an array of EffectDeletionTarget entries describing which effects to remove. If the effects array argument is empty, there is nothing to delete, so it throws immediately before parsing the AST. This is a guard against no-op API calls that would otherwise produce misleading results.","triggerScenarios":"Calling deleteEffects({effects: [], input}) directly; calling the public deleteEffect wrapper after it built an empty selection; batch delete where all targets were filtered out (e.g. already-deleted effects removed from the list) leaving an empty array.","commonSituations":"UI batch-delete where the selection was cleared but the button stayed enabled; deduplication logic removing all duplicate targets; programming error passing a computed list that ends up empty.","solutions":["Check effects.length > 0 before calling deleteEffects and no-op otherwise.","Fix the filtering/dedup step that emptied the target list.","If using the single-effect deleteEffect wrapper, ensure an effectIndex/sequenceNodePath was actually supplied."],"exampleFix":"// before\nawait deleteEffects({input, effects: selectedEffects});\n// after\nif (selectedEffects.length > 0) {\n  await deleteEffects({input, effects: selectedEffects});\n}","handlingStrategy":"validation","validationCode":"if (effects.length === 0) return input; // no-op\nawait deleteEffects({input, effects});","typeGuard":"const hasDeletionTargets = (\n  effects: EffectDeletionTarget[],\n): effects is [EffectDeletionTarget, ...EffectDeletionTarget[]] => effects.length > 0;","tryCatchPattern":"try {\n  await deleteEffects({input, effects});\n} catch (e) {\n  if (e instanceof Error && e.message === 'No effects were specified for deletion') return input;\n  throw e;\n}","preventionTips":["Disable delete buttons when the selection is empty.","No-op early when filtering leaves zero targets."],"tags":["empty-input","validation","studio"],"backgroundTag":"empty-required-field","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"}