{"record":{"id":"973a933f58e9a3e2","repo":"BloopAI/vibe-kanban","slug":"error-message-failed-to-bulk-update-projects","errorCode":null,"errorMessage":"error.message || 'Failed to bulk update projects' (dynamic)","messagePattern":"error\\.message \\|\\| 'Failed to bulk update projects' \\(dynamic\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/remoteApi.ts","lineNumber":121,"sourceCode":"}\n\nexport interface BulkUpdateProjectItem {\n  id: string;\n  changes: Partial<UpdateProjectRequest>;\n}\n\nexport async function bulkUpdateProjects(\n  updates: BulkUpdateProjectItem[]\n): Promise<void> {\n  const response = await makeRequest('/v1/projects/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 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","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/remoteApi.ts#L103-L139","documentation":"bulkUpdateProjects PATCHes multiple project changes to the remote API. On a non-ok HTTP response it parses the response JSON and throws Error with the server-provided `message`, falling back to the generic 'Failed to bulk update projects' string when the error body has no message field (or the body is not JSON). The thrown value is the rejection of the returned Promise<void>.","triggerScenarios":"Any non-2xx response from PATCH bulk-update-projects: validation failures on one of the update items, stale/invalid auth token, project id not found, or server 500. Also fires when the server returns an error body without a `message` property.","commonSituations":"Expired JWT after idle time, bulk-pasting a list containing already-deleted project ids, self-hosted gateway returning HTML error pages (JSON parse then fallback message), rate limiting under a large batch.","solutions":["Re-authenticate / refresh the session token and retry the request","Log the caught error.message and response status to identify which update item the server rejected; validate ids exist before batching","Reduce batch size or split updates to isolate the failing item","If self-hosted, verify VITE_VK_SHARED_API_BASE points to a healthy backend returning JSON errors"],"exampleFix":"// before\nawait bulkUpdateProjects(updates); // unhandled rejection\n// after\ntry {\n  await bulkUpdateProjects(updates);\n} catch (e) {\n  notify.error(e instanceof Error ? e.message : 'Bulk update failed');\n}","handlingStrategy":"try-catch","validationCode":"if (!updates.length) return; const ids = new Set(projects.map(p => p.id)); if (updates.some(u => !ids.has(u.id))) throw new Error('unknown project id in batch');","typeGuard":"function isApiErrorBody(x: unknown): x is { message: string } { return typeof x === 'object' && x !== null && typeof (x as any).message === 'string'; }","tryCatchPattern":"try {\n  await bulkUpdateProjects(updates);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : 'Failed to bulk update projects';\n  notify.error(msg);\n}","preventionTips":["Keep auth tokens fresh; rely on makeRequest's 401 retry but handle its exhaustion","Validate all update ids against freshly fetched project data before batching","Keep batches small to isolate server-side validation failures","Always await the promise inside try/catch — it rejects, it never resolves with an error"],"tags":["http","bulk-update","api-client"],"backgroundTag":"http-request-failed","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}