BloopAI/vibe-kanban · error
Failed to create ${mutation.name} (or server-provided messag
Error message
Failed to create ${mutation.name} (or server-provided message via parseResponseError) What it means
The onInsert mutation handler POSTs each inserted row to mutation.url and, on a non-ok response, throws an Error whose message comes from parseResponseError — the server's `message`/`error` field, or the fallback 'Failed to create <name>'. This aborts the optimistic transaction, so Electric rolls back the local insert.
Source
Thrown at packages/web-core/src/shared/lib/electric/collections.ts:643
) {
return {
onInsert: async ({
transaction,
}: MutationFnParams): Promise<{ txid: number[] } | void> => {
const txids = await Promise.all(
transaction.mutations.map(async (mutationItem) => {
const data = mutationItem.modified as Record<string, unknown>;
const response = await makeRequest(mutation.url, {
method: 'POST',
body: JSON.stringify(data),
});
if (!response.ok) {
const message = await parseResponseError(
response,
`Failed to create ${mutation.name}`
);
throw new Error(message);
}
const result = (await response.json()) as { txid: number };
return result.txid;
})
);
maybeRefreshFallbackAfterMutation(sourceKey);
if (isSourceFallbackLocked(sourceKey)) {
return;
}
return { txid: txids };
},
onUpdate: async ({
transaction,View on GitHub (pinned to 4deb7eca8f)
Solutions
- Read the thrown message — it usually contains the server's validation reason (parseResponseError surfaced it).
- Validate the row against server schema before optimistic insert (zod schema shared via shared/schemas).
- Handle 401 by refreshing auth and retrying the transaction.
- Confirm mutation.url is the correct create endpoint and accepts the exact JSON body being sent.
Example fix
// before
await collection.insert(data); // throws on server rejection
// after
const parsed = taskCreateSchema.safeParse(data);
if (!parsed.success) { showError(parsed.error); return; }
await collection.insert(parsed.data); Defensive patterns
Strategy: try-catch
Validate before calling
const parsed = createSchema.safeParse(data);
if (!parsed.success) {
showError(parsed.error.message);
return;
} Type guard
function isCreateFailure(msg: string): boolean {
return msg.startsWith('Failed to create ');
} Try / catch
try {
await collection.insert(data);
} catch (e) {
if (isCreateFailure(e.message)) {
showToast(e.message); // server-provided reason surfaced by parseResponseError
return; // optimistic insert is rolled back automatically
}
throw e;
} Prevention
- Validate against the shared zod schema before optimistic insert
- Keep mutation.url in sync with the backend create route
- Refresh auth tokens proactively to avoid mid-edit 401s
- Check server-side uniqueness constraints client-side first
When it happens
Trigger: POST to the mutation endpoint fails validation (400/422), user lacks permission (403), session expired (401), the record conflicts (409), or the route returns 500; also thrown per-item inside Promise.all so any one failing insert rejects the whole transaction.
Common situations: Required field missing from the new row per server-side validation; optimistic UI allowed an edit the server rejects; token expired mid-session; server enforces uniqueness the client didn't check; mutation.url points at a stale/wrong API path after refactor.
Related errors
- Failed to update ${mutation.name}: missing key
- Failed to bulk update ${mutation.name} (or server-provided m
- Fallback response for "${table}" is not an object
- Fallback response missing "${table}" array
- Failed to fetch fallback ${args.shape.table} (or server-prov
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/681ba0d343c7f14f.
Report an issue: GitHub.