diff --git a/app/src/components/StoriesTab/StoryTrackEditor.tsx b/app/src/components/StoriesTab/StoryTrackEditor.tsx index ef20bf95..641ad048 100644 --- a/app/src/components/StoriesTab/StoryTrackEditor.tsx +++ b/app/src/components/StoriesTab/StoryTrackEditor.tsx @@ -500,7 +500,7 @@ export function StoryTrackEditor({ storyId, items }: StoryTrackEditorProps) { }, [trimmingItem, trimSide, tempTrimValues, storyId, trimItem, toast]); const handleSplit = useCallback(() => { - if (!selectedClipId) return; + if (!selectedClipId || splitItem.isPending) return; const item = items.find((i) => i.id === selectedClipId); if (!item) return; diff --git a/backend/services/stories.py b/backend/services/stories.py index 611ab29d..cb7a46ef 100644 --- a/backend/services/stories.py +++ b/backend/services/stories.py @@ -484,13 +484,15 @@ async def split_story_item( Returns: List of two updated item details (original and new) or None if not found/invalid """ - # Get the item + # Get the item with a row lock to prevent concurrent splits on the + # same clip (e.g. from rapid double-clicks racing each other). item = ( db.query(DBStoryItem) .filter_by( id=item_id, story_id=story_id, ) + .with_for_update() .first() ) if not item: