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

  1. Return the rows directly under the table-name key as a JSON array: { "<table>": [...] }.
  2. Align the ShapeDefinition.table string with the server's response key.
  3. Guard the server handler against returning null for empty datasets (use []).
  4. 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

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


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/9eef84d22ea4bab7. Report an issue: GitHub.