cycle: concurrent add-issue requests cause IntegrityError - bulk_create missing ignore_conflicts unlike module equivalent
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 59.6k
- Forks
- 5.8k
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 49
Description
Bug Description
CycleIssueViewSet.create uses ulk_create without ignore_conflicts=True. The CycleIssue model has a partial unique constraint cycle_issue_when_deleted_at_null on (cycle, issue) where deleted_at IS NULL. Two concurrent POST requests adding the same issue to the same cycle both pass the existing-issue check (plain ilter, no row lock) and then both call ulk_create. The second request raises an IntegrityError and returns HTTP 500.
The inconsistency is clear: ModuleIssueViewSet.create_module_issues in module/issue.py (line 237) performs the identical operation with ignore_conflicts=True. The cycle equivalent never received the same fix.
Affected file
pps/api/plane/app/views/cycle/issue.py, line 264:
python created_records = CycleIssue.objects.bulk_create( [CycleIssue(...) for issue in new_issues], batch_size=10, # missing ignore_conflicts=True )
For comparison, pps/api/plane/app/views/module/issue.py line 237:
python CycleIssue.objects.bulk_create(records, batch_size=10, ignore_conflicts=True)
Failure scenario
Two browser tabs open the same cycle simultaneously. Both click "Add issues" with overlapping issue selections. Both POST requests read no existing CycleIssue rows (race), both call ulk_create, the second throws IntegrityError, user sees a 500 error and must retry.
Fix
python created_records = CycleIssue.objects.bulk_create( [CycleIssue(...) for issue in new_issues], batch_size=10, ignore_conflicts=True, )
Environment
Plane develop branch (2026-08-13).
Contributor guide
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 in apps/api/plane/app/views/cycle/issue.py at line 264 and compare the bulk_create call with create_module_issues in module/issue.py line 237. Reproduce or inspect the concurrent duplicate-add scenario, then verify that overlapping requests no longer return HTTP 500 and that the cycle behavior matches the module equivalent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- api, backend, databases
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 86/100