{"record":{"id":"421c273c5de174fd","repo":"BloopAI/vibe-kanban","slug":"failed-to-update-mutation-name-missing-key","errorCode":null,"errorMessage":"Failed to update ${mutation.name}: missing key","messagePattern":"Failed to update (.+?): missing key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/electric/collections.ts","lineNumber":668,"sourceCode":"\n      maybeRefreshFallbackAfterMutation(sourceKey);\n\n      if (isSourceFallbackLocked(sourceKey)) {\n        return;\n      }\n\n      return { txid: txids };\n    },\n\n    onUpdate: async ({\n      transaction,\n    }: MutationFnParams): Promise<{ txid: number[] } | void> => {\n      let txids: number[] = [];\n\n      if (transaction.mutations.length > 1) {\n        const updates = transaction.mutations.map((mutationItem) => {\n          if (!mutationItem.key) {\n            throw new Error(`Failed to update ${mutation.name}: missing key`);\n          }\n\n          return {\n            id: String(mutationItem.key),\n            ...(mutationItem.changes as Record<string, unknown>),\n          };\n        });\n\n        const response = await makeRequest(`${mutation.url}/bulk`, {\n          method: 'POST',\n          body: JSON.stringify({ updates }),\n        });\n\n        if (!response.ok) {\n          const message = await parseResponseError(\n            response,\n            `Failed to bulk update ${mutation.name}`\n          );","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/electric/collections.ts#L650-L686","documentation":"In the onUpdate mutation handler, when a transaction contains multiple mutations the library builds a bulk-update payload; each mutation item must carry a row key, and this error is thrown for any item whose `key` is undefined/null. Without a key the library cannot construct the { id, ...changes } entry for the bulk endpoint.","triggerScenarios":"An update transaction where mutationItem.key is missing — typically updating a row that was inserted optimistically and not yet persisted/assigned an ID, or rows whose primary key field isn't mapped as the Electric key (e.g. id is undefined in the row object).","commonSituations":"Batch-editing rows that were just created offline and have client-generated/undefined keys; selecting rows whose key field is named differently than the collection's id; a bug where insert txid wasn't awaited before the subsequent update in the same transaction.","solutions":["Ensure every row has a stable primary key (`id`) before it can be updated; generate the key client-side on optimistic insert.","Await the insert (or refresh) so the server-assigned key is present before issuing updates.","Filter out or reject updates for keyless rows in the UI before opening the transaction.","Verify the collection's schema maps the correct field as the Electric primary key."],"exampleFix":"// before\nawait Promise.all(rows.map(r => collection.update({ id: r.uid, ...changes })));\n// after\nconst updatable = rows.filter(r => r.id != null);\nif (updatable.length !== rows.length) warnUser('Some rows have no ID and were skipped');\nawait Promise.all(updatable.map(r => collection.update({ id: r.id, ...changes })));","handlingStrategy":"validation","validationCode":"const missing = rows.filter(r => r.id == null);\nif (missing.length > 0) {\n  throw new Error(`${missing.length} row(s) have no primary key and cannot be updated`);\n}","typeGuard":"function hasKey(m: { key?: string | number }): m is { key: string | number } {\n  return m.key != null;\n}","tryCatchPattern":"try {\n  await runBatchUpdate(collection, rows);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('missing key')) {\n    showToast('Some selected rows were never saved and cannot be edited');\n    return;\n  }\n  throw e;\n}","preventionTips":["Generate client-side IDs (uuid) on optimistic inserts so keys always exist","Only enable edit controls on rows with a non-null key","Await insert completion before allowing updates on new rows","Map the collection schema's key to the actual primary-key field"],"tags":["electric-sql","mutations","missing-key","validation"],"backgroundTag":"missing-primary-key","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}