BloopAI/vibe-kanban · error
Fallback response missing "${table}" array
Error message
Fallback response missing "${table}" array What it means
extractFallbackRows throws this when the fallback payload is an object but does not contain an array under the payload[table] key. The library expects each fallback response to embed the row list under the exact table name; a missing, null, or non-array value means the sync snapshot cannot be built.
Source
Thrown at packages/web-core/src/shared/lib/electric/collections.ts:417
metadata: {},
});
}
syncParams.commit();
syncParams.markReady();
}
function extractFallbackRows(
payload: unknown,
table: string
): Array<ElectricRow> {
if (!payload || typeof payload !== 'object') {
throw new Error(`Fallback response for "${table}" is not an object`);
}
const rows = (payload as Record<string, unknown>)[table];
if (!Array.isArray(rows)) {
throw new Error(`Fallback response missing "${table}" array`);
}
return rows as Array<ElectricRow>;
}
async function parseResponseError(
response: Response,
fallbackMessage: string
): Promise<string> {
try {
const body = (await response.json()) as {
message?: string;
error?: string;
};
return body.message || body.error || fallbackMessage;
} catch {
return fallbackMessage;
}View on GitHub (pinned to 4deb7eca8f)
Solutions
- Return the rows directly under the table-name key as a JSON array: { "<table>": [...] }.
- Align the ShapeDefinition.table string with the server's response key.
- Guard the server handler against returning null for empty datasets (use []).
- Add a response contract test for the fallback endpoint.
Example fix
// before (server)
res.json({ data: rows });
// after (server)
res.json({ tasks: rows ?? [] }); // key must match shape.table, value must be an array Defensive patterns
Strategy: validation
Validate before calling
const payload = await response.json();
if (!Array.isArray(payload?.[table])) {
throw new Error(`Fallback response must contain a "${table}" array`);
} Type guard
function hasTableRows(payload: unknown, table: string): payload is { [k: string]: unknown } & Record<typeof table, ElectricRow[]> {
return typeof payload === 'object' && payload !== null &&
Array.isArray((payload as Record<string, unknown>)[table]);
} Try / catch
try {
const rows = extractFallbackRows(payload, table);
} catch (e) {
console.error('Fallback contract violation:', e.message, 'payload keys:', Object.keys(payload ?? {}));
} Prevention
- Return rows under the exact table-name key as an array
- Use [] instead of null for empty datasets
- Rename table + endpoint key together when refactoring
- Add a shared zod schema for the fallback envelope
When it happens
Trigger: Server response uses a different key ('data', 'items', 'rows') instead of the table name; the table key is present but null; pagination envelope like { tasks: { rows: [...] } }; empty response object {} from a handler that forgot to include rows.
Common situations: API contract drift after backend refactor; table renamed in Electric shape but not in the REST endpoint (or vice versa); endpoint returning { tasks: null } for 'no data'; developer implementing a new fallback route against the wrong response contract.
Related errors
- Fallback response for "${table}" is not an object
- Failed to fetch fallback ${args.shape.table} (or server-prov
- Failed to create ${mutation.name} (or server-provided messag
- Failed to update ${mutation.name}: missing key
- Failed to list projects (${res.status})
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/9eef84d22ea4bab7.
Report an issue: GitHub.