From 3a6b8458177447972d57e9b4380be21dd7487dbc Mon Sep 17 00:00:00 2001 From: eeshsaxena <139802361+eeshsaxena@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:26:16 +0530 Subject: [PATCH 1/2] fix(cycle): ignore_conflicts on add-issue bulk_create to avoid 500 on concurrent adds --- apps/api/plane/app/views/cycle/issue.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/api/plane/app/views/cycle/issue.py b/apps/api/plane/app/views/cycle/issue.py index e4fb00ca2a4..1383794728c 100644 --- a/apps/api/plane/app/views/cycle/issue.py +++ b/apps/api/plane/app/views/cycle/issue.py @@ -274,6 +274,12 @@ def create(self, request, slug, project_id, cycle_id): for issue in new_issues ], batch_size=10, + # Concurrent add-issue requests can both pass the unlocked + # existing-issue check above and insert the same (cycle, issue), + # violating the cycle_issue_when_deleted_at_null unique constraint. + # Skip the duplicates instead of raising, matching the module and + # external-API equivalents. + ignore_conflicts=True, ) # Updated Issues From 668e89b8d6faafb88468b1a0c39f6fdebb776231 Mon Sep 17 00:00:00 2001 From: eeshsaxena <139802361+eeshsaxena@users.noreply.github.com> Date: Sun, 16 Aug 2026 08:26:15 +0530 Subject: [PATCH 2/2] fix(cycle): drop skipped (pk=None) rows from created-issue activity ON CONFLICT DO NOTHING leaves skipped rows with pk=None; filtering them out of created_records avoids logging a 'created' activity entry for an insert that was discarded under a concurrent add (per review). --- apps/api/plane/app/views/cycle/issue.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/api/plane/app/views/cycle/issue.py b/apps/api/plane/app/views/cycle/issue.py index 1383794728c..6aeb3f7dfdb 100644 --- a/apps/api/plane/app/views/cycle/issue.py +++ b/apps/api/plane/app/views/cycle/issue.py @@ -282,6 +282,12 @@ def create(self, request, slug, project_id, cycle_id): ignore_conflicts=True, ) + # ON CONFLICT DO NOTHING does not populate PKs on skipped rows, so a + # concurrent request that lost the race gets its duplicates back here + # with pk=None. Drop them before the activity log below, otherwise it + # records a "created" entry for an insert that was silently discarded. + created_records = [record for record in created_records if record.pk is not None] + # Updated Issues updated_records = [] update_cycle_issue_activity = []