remotion-dev/remotion · error · Error
No keyframe changes were specified
Error message
No keyframe changes were specified
What it means
mutateKeyframesInProject powers the sequence and effect keyframe operations (move/add/delete keyframes). It refuses no-op calls: when both sequenceMutations and effectMutations are empty arrays it throws instead of committing an empty change and polluting the undo stack.
Source
Thrown at packages/browser-studio/src/browser-studio-operations.ts:513
onProjectChange(project);
refreshDefaultPropsSubscriptions();
if (!metadata.skipSequencePropsUpdate) {
refreshSequencePropsSubscriptions();
}
},
});
const mutateKeyframesInProject = async ({
project,
sequenceMutations,
effectMutations,
}: {
project: VirtualProject;
sequenceMutations: SequenceKeyframeMutation[];
effectMutations: EffectKeyframeMutation[];
}) => {
if (sequenceMutations.length === 0 && effectMutations.length === 0) {
throw new Error('No keyframe changes were specified');
}
const mergeUpdates = <T extends SequenceKeyframeUpdate>(updates: T[]) => {
const merged: T[] = [];
for (const update of updates) {
const existingMove = merged.find(
(candidate) =>
candidate.key === update.key &&
candidate.operation.type === 'move' &&
update.operation.type === 'move',
);
if (
existingMove?.operation.type === 'move' &&
update.operation.type === 'move'
) {
existingMove.operation.moves.push(...update.operation.moves);
} else {
merged.push(update);View on GitHub (pinned to b2f4e34732)
Solutions
- Skip the operation call when both mutation arrays are empty — treat it as a no-op.
- Fix the upstream filtering so intended keyframe changes survive into the request.
- Keep UI state unchanged on empty batches instead of surfacing the error to the user.
Example fix
// before
await saveKeyframes({sequenceMutations: filtered, effectMutations: []});
// after
if (filtered.length > 0) {
await saveKeyframes({sequenceMutations: filtered, effectMutations: []});
} Defensive patterns
Strategy: validation
Validate before calling
const hasChanges =
sequenceMutations.length > 0 || effectMutations.length > 0;
if (hasChanges) {
await commitKeyframes({sequenceMutations, effectMutations});
} Prevention
- Short-circuit gesture end handlers when nothing effectively changed.
- Keep a dirty flag and only call keyframe save APIs when at least one edit is pending.
- Unit-test batching logic with de-duplicated inputs to ensure the batch is never emptied.
When it happens
Trigger: Invoking a keyframe mutation operation (via commitKeyframeMutations consumers such as updateSequenceKeyframes-style flows) after client-side filtering removed every requested change, leaving zero mutations in both arrays.
Common situations: Drag handlers that end without an effective change; batching logic that de-duplicates updates and accidentally empties the batch; gesture code that always calls save even when nothing moved.
Related errors
- No effects were specified for deletion
- No effects were specified for duplication
- No effect prop edits to save
- No packages were specified
- No JSX nodes were specified for deletion
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-08-22).
Data as JSON: /api/errors/d176ec63c611990e.
Report an issue: GitHub.