{"record":{"id":"ebc405920ac96cab","repo":"BloopAI/vibe-kanban","slug":"failed-to-bulk-update-issues","errorCode":null,"errorMessage":"Failed to bulk update issues","messagePattern":"Failed to bulk update issues","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/remoteApi.ts","lineNumber":136,"sourceCode":"  });\n  if (!response.ok) {\n    const error = await response.json();\n    throw new Error(error.message || 'Failed to bulk update projects');\n  }\n}\n\nexport async function bulkUpdateIssues(\n  updates: BulkUpdateIssueItem[]\n): Promise<void> {\n  const response = await makeRequest('/v1/issues/bulk', {\n    method: 'POST',\n    body: JSON.stringify({\n      updates: updates.map((u) => ({ id: u.id, ...u.changes })),\n    }),\n  });\n  if (!response.ok) {\n    const error = await response.json();\n    throw new Error(error.message || 'Failed to bulk update issues');\n  }\n}\n\nexport interface BulkUpdateProjectStatusItem {\n  id: string;\n  changes: Partial<UpdateProjectStatusRequest>;\n}\n\nexport async function bulkUpdateProjectStatuses(\n  updates: BulkUpdateProjectStatusItem[]\n): Promise<void> {\n  const response = await makeRequest('/v1/project_statuses/bulk', {\n    method: 'POST',\n    body: JSON.stringify({\n      updates: updates.map((u) => ({ id: u.id, ...u.changes })),\n    }),\n  });\n  if (!response.ok) {","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/remoteApi.ts#L118-L154","documentation":"bulkUpdateIssues sends a batch of issue changes to the remote API and, if the response is not ok, throws Error(serverMessage || 'Failed to bulk update issues'). It is the issue-tracker equivalent of the project bulk-update error and surfaces server-side rejection reasons verbatim when present. Called from Actions and handleDragEnd (drag-and-drop persistence).","triggerScenarios":"Non-ok HTTP response from the bulk-update-issues endpoint: a dragged issue's status/triage change rejected (deleted issue, invalid field value), auth failure, or backend error; also when the error body lacks a `message`.","commonSituations":"Drag-and-drop onto a column whose status value the server no longer accepts after a schema change; stale issue ids after another user deleted them; 401 from expired session mid-drag.","solutions":["Check the thrown error.message / network tab for the real server reason","Refresh the issue list (re-fetch) to clear stale ids, then retry the drag/update","Re-authenticate if the status was 401; the client's makeRequest retryOn401 may already have been exhausted","Handle the error in handleDragEnd to roll back optimistic UI state"],"exampleFix":"// before\nonDragEnd={handleDragEnd} // throws unhandled\n// after\nconst handleDragEnd = async (e) => {\n  try { await applyDrag(e); }\n  catch (err) { notify.error(err.message); refetchIssues(); }\n};","handlingStrategy":"try-catch","validationCode":"const liveIds = new Set(issues.map(i => i.id));\nif (updates.some(u => !liveIds.has(u.id))) { await refetchIssues(); return; }","typeGuard":"function isBulkUpdateItem(u: unknown): u is BulkUpdateIssueItem { return typeof u === 'object' && u !== null && typeof (u as any).id === 'string'; }","tryCatchPattern":"try {\n  await bulkUpdateIssues(updates);\n} catch (e) {\n  rollbackOptimisticChanges(updates);\n  notify.error(e instanceof Error ? e.message : 'Failed to bulk update issues');\n}","preventionTips":["Wrap every handleDragEnd in try/catch with optimistic-UI rollback","Re-fetch issues after errors so deleted ids are pruned from local state","Don't cache update batches across renders; build them from fresh state"],"tags":["http","bulk-update","drag-and-drop"],"backgroundTag":"http-request-failed","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}