{"record":{"id":"13db20ac1a94ca92","repo":"remotion-dev/remotion","slug":"no-effect-prop-edits-to-save","errorCode":null,"errorMessage":"No effect prop edits to save","messagePattern":"No effect prop edits to save","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-studio/src/browser-studio-operations.ts","lineNumber":1165,"sourceCode":"\t\t\t\tfiles: {...project.files, [absolutePath]: result.output},\n\t\t\t};\n\t\t\tcontroller.applyMutation({\n\t\t\t\ttimelineSelection: null,\n\t\t\t\tfileName: absolutePath,\n\t\t\t\tnodePathMutationFiles: null,\n\t\t\t\tmutate: () => nextProject,\n\t\t\t});\n\t\t\treturn getEffectStatus({\n\t\t\t\teffectIndex: request.effectIndex,\n\t\t\t\tfileName: request.fileName,\n\t\t\t\tproject: nextProject,\n\t\t\t\tschema: request.schema,\n\t\t\t\tsequenceNodePath: request.sequenceNodePath,\n\t\t\t});\n\t\t},\n\t\tsaveMultipleEffectProps: async (request) => {\n\t\t\tif (request.edits.length === 0) {\n\t\t\t\tthrow new Error('No effect prop edits to save');\n\t\t\t}\n\n\t\t\tconst project = getProject();\n\t\t\tconst outputByPath = new Map<string, string>();\n\t\t\tfor (const edit of request.edits) {\n\t\t\t\tconst absolutePath = findProjectFile({\n\t\t\t\t\tfilePath: edit.fileName,\n\t\t\t\t\tproject,\n\t\t\t\t});\n\t\t\t\tconst result = await updateEffectPropsCodemod({\n\t\t\t\t\teffectIndex: edit.effectIndex,\n\t\t\t\t\tformatFile: formatCodemodFile,\n\t\t\t\t\tinput: outputByPath.get(absolutePath) ?? project.files[absolutePath],\n\t\t\t\t\tschema: edit.schema,\n\t\t\t\t\tsequenceNodePath: edit.sequenceNodePath.nodePath,\n\t\t\t\t\tupdate:\n\t\t\t\t\t\tedit.type === 'effect-param'\n\t\t\t\t\t\t\t? {","sourceCodeStart":1147,"sourceCodeEnd":1183,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/browser-studio/src/browser-studio-operations.ts#L1147-L1183","documentation":"saveMultipleEffectProps refuses empty batch saves: if request.edits is an empty array it throws 'No effect prop edits to save'. Unlike most other operations here, this method has no try/catch wrapper, so the error propagates as a rejected promise to the caller.","triggerScenarios":"Calling saveMultipleEffectProps({edits: [], ...}) — e.g. a bulk property-save flow where all pending edits were committed individually first, leaving an empty batch.","commonSituations":"Debounced auto-save that fires after the edit buffer was already flushed; form submit handlers that always call save even with no dirty fields.","solutions":["Guard the call: only invoke saveMultipleEffectProps when edits.length > 0.","Clear or check the dirty-edit buffer before submitting.","Wrap the call in try/catch since this operation returns a raw rejection, unlike the structured-error operations."],"exampleFix":"// before\nawait operations.effect.saveMultipleEffectProps({edits, undoLabel: 'Edit props'});\n\n// after\nif (edits.length > 0) {\n  await operations.effect.saveMultipleEffectProps({edits, undoLabel: 'Edit props'});\n}","handlingStrategy":"try-catch","validationCode":"if (request.edits.length > 0) {\n  await operations.effect.saveMultipleEffectProps(request);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await operations.effect.saveMultipleEffectProps(request);\n} catch (error) {\n  if (error instanceof Error && error.message === 'No effect prop edits to save') {\n    return; // no-op save, nothing to do\n  }\n  throw error;\n}","preventionTips":["This operation is not wrapped in a structured-error handler — always try/catch it.","Track dirty edits and skip the call when the buffer is empty.","Clear the edit buffer atomically after each successful save."],"tags":["effects","props","validation","no-op"],"backgroundTag":"empty-request-rejected","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-08-22T21:45:17.748Z","contentChangedAt":"2026-08-22T21:45:17.748Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}