OpenCut-app / OpenCut-app/OpenCut
[BUG] Project rename/delete races can lose data and report failed persistence as success
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 89.8k
- Forks
- 8.9k
- PR merge metrics
- No merged PRs in 30d
Description
[BUG] Project rename/delete races can lose data and report failed persistence as success
Platform
Web editor using the browser storage adapters (OPFS and IndexedDB), current official dev at c2e266870172312f461df75da3e7f6fbe9d2a1fc.
Browser
Any supported browser; reproduced deterministically with delayed/rejecting storage-adapter promises.
Current Behavior
Project rename and deletion are not ordered with autosave or with each other, and their public methods do not expose failures to callers.
Current dev evidence:
SaveManager.saveNow()callsProjectManager.saveCurrentProject()while tracking only a process-wideisSavingflag (apps/web/src/core/managers/save-manager.ts).ProjectManager.saveCurrentProject()snapshotsthis.active, awaitsstorageService.saveProject({ project: updatedProject }), then assigns that captured snapshot back tothis.activeand metadata (project-manager.ts,saveCurrentProject).ProjectManager.renameProject()independently reloads the project, changesname/updatedAt, saves it, and then publishes it (project-manager.ts,renameProject). There is no shared per-project fence or generation/currentness check between these operations.ProjectManager.deleteProjects()runsstorageService.deleteProjectMedia()andstorageService.deleteProject()concurrently for each ID withPromise.all. A failure can therefore leave either the project record or its media behind without a deterministic phase result.- Both
renameProject()anddeleteProjects()catch persistence errors internally and resolvePromise<void>. Consequently,apps/web/src/app/projects/page.tsxclears selection and closes delete/rename dialogs after an unsuccessful operation.apps/web/src/components/editor/editor-header.tsxcan also route to/projectsafter a failed active-project deletion because itscatchnever receives the swallowed error.
A delayed pre-rename autosave can overwrite and republish the old name after rename reports success. A delete can remove the record while media deletion fails (or remove media while record deletion fails), while the UI cannot distinguish confirmed deletions from failures.
Expected Behavior
Rename and delete should use the same per-project persistence coordinator introduced by the save-durability work, with deterministic outcomes:
- Rename acquires an exclusive project fence before awaiting, drains older saves, derives from the current canonical project (or a fresh durable load), changes only
nameandupdatedAt, and publishes only after a successful, still-current commit. - Delete sorts and deduplicates IDs, closes admission before awaiting, drains registered project work, then deletes each target in a fixed order: media bytes, media metadata, project record.
- Each delete result identifies the project ID, failed phase, error/attempt count, and whether record deletion was confirmed. Confirmed record deletion leaves a coordinator tombstone so late saves/renames cannot recreate the project.
- A pre-record failure reconciles durable state before reopening admission. Mixed batches remove only confirmed IDs from memory/selection and allow retry of failed IDs.
- Manager methods return/throw typed outcomes; one caller owns the toast and changes dialogs, selection, or route only for confirmed success.
This should consume the shared coordinator/fence from the separate save-durability candidate rather than introducing a second mutex or caller-only wait.
Recurrence Probability
Always, when the relevant adapter promises are delayed or rejected in the described order.
Steps To Reproduce
Rename overwritten by an older autosave
- Open project A named
Originaland make a timeline change soSaveManagerstartssaveCurrentProject(). - Delay that autosave's
storageService.saveProject()after it captures the project snapshot. - Rename A to
Renamedand allowrenameProject()'s load/save to complete. - Release the older autosave.
- Inspect the active project, projects metadata, raw stored project, and a fresh-manager reload.
- Observe that the older snapshot can restore/persist
Originaleven though rename already reported success.
Partial deletion reported as success
- Create a project with at least one persisted media asset.
- Make
deleteProjectMedia({ projectId })reject whiledeleteProject({ id })succeeds (repeat with the opposite failure). - Delete from the projects page or editor header.
- Inspect project metadata, raw project/media stores, selection/dialog state, route, and a fresh-manager reload.
- Observe a half-deleted project and that
deleteProjects()resolves after logging the failure, allowing the caller to present success behavior.
Anything else?
Impact
This can silently undo a successful rename, resurrect stale active state, orphan project/media data, or navigate/clear selection after persistence failed. Retrying without a durable deletion fence can race another autosave and recreate a deleted project.
Bounded proposed fix
Limit this issue to project record mutation ordering and typed caller outcomes in ProjectManager, storage deletion helpers, the shared coordinator, and the projects/editor mutation controllers. Media-operation FIFO and object-URL reconciliation remain separate follow-up work; delete should expose the registration/drain boundary that follow-up can extend.
Focused acceptance tests
- Deferred autosave followed by rename: durable reload keeps the new name and newer timeline state in both completion orders.
- Save rejection before rename; dirty work during rename; rename failure leaves memory unchanged and yields one caller toast.
- Active delete and projects-page delete while save/close work is pending.
- Post-tombstone late save and rename never reach storage adapters or recreate the record.
- Bytes, media-metadata, and project-record deletion failures each return the exact typed phase and preserve retryable UI state.
- Two-ID mixed batch removes/routes only confirmed IDs, retains failed selection, and retry completes only failed IDs.
- Fresh manager confirms successful deletion is absent and pre-record failure is reconciled.
Duplicate search
Searched all OpenCut issues for rename delete project, project deletion storage, project rename, data loss rename, autosave delete project, and delete project failure. No matching issue was found. The closest results are unrelated: #413 (https://github.com/OpenCut-app/OpenCut/issues/413) requested the editor rename UI and is closed; #192 (https://github.com/OpenCut-app/OpenCut/issues/192) concerns the OpenCut product name/trademark.
Because the contribution guide accepts critical fixes only case by case, please confirm candidate-specific maintainer approval and the shared-coordinator ownership before implementation begins.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/web/src/core/managers/save-manager.ts and project-manager.ts, then inspect the mutation callers in apps/web/src/app/projects/page.tsx and apps/web/src/components/editor/editor-header.tsx. Read the shared coordinator from the save-durability work before tracing rename, save, and delete ordering. Done means the focused acceptance tests cover typed failures, confirmed deletion, mixed batches, and late saves or renames cannot overwrite or recreate projects.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- database, full-stack
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100