drawdb-io/drawdb · error · Error
The AI import returned no tables.
Error message
The AI import returned no tables.
What it means
Thrown by normalizeAiDiagram at the top of normalization as a hard precondition: the AI payload must be a non-null object whose `tables` is a non-empty array. It fails fast before any type/relationship resolution so downstream code never iterates an undefined or empty table list. The single source site is the guard `if (!raw || !Array.isArray(raw.tables) || !raw.tables.length)` at src/utils/importAiDiagram.js:59.
Source
Thrown at src/utils/importAiDiagram.js:60
const declared = declaredNames.get(upper);
if (declared) return { type: declared };
for (const alias of TYPE_ALIASES[upper] ?? []) {
if (validTypes[alias]) return { type: alias };
}
const fallback = FALLBACK_TYPES.find((candidate) => validTypes[candidate]);
return {
type: fallback ?? upper,
warning: trimmed
? `Type "${trimmed}" is not available for this database, imported as ${fallback}.`
: `A column had no type, imported as ${fallback}.`,
};
}
export function normalizeAiDiagram(raw, database) {
if (!raw || !Array.isArray(raw.tables) || !raw.tables.length) {
throw new Error("The AI import returned no tables.");
}
const warnings = [];
const validTypes = dbToTypes[database] || {};
const enums = Array.isArray(raw.enums) ? raw.enums : [];
const types = Array.isArray(raw.types) ? raw.types : [];
const declaredNames = new Map();
for (const entry of [...enums, ...types]) {
if (entry?.name) declaredNames.set(String(entry.name).toUpperCase(), entry.name);
}
const tables = raw.tables.map((table) => ({
...table,
fields: (table.fields ?? []).map((field) => {
const { type, warning } = resolveType(field.type, validTypes, declaredNames);
if (warning) warnings.push(warning);
return { ...field, type };View on GitHub (pinned to e7086e7fc2)
Solutions
- Log `result.diagram` (keys + `tables?.length`) right before the call in Modal.jsx:203 to see exactly what the AI returned.
- Add an explicit pre-check in `importSourceWithAi` and surface a user-facing 'AI returned no tables' error without invoking normalizeAiDiagram.
- Inspect the AI service call (`importSqlWithAi`) for non-2xx / empty-body / parse-failure paths that silently resolve to an object without `tables`.
- Tighten the system prompt sent to the AI to always emit `{ "tables": [ ... ], ... }` with at least one table, and validate the parsed JSON contract.
- Retry the AI request once on a detected empty payload before reporting a hard failure.
Example fix
// before
const { diagram, warnings } = normalizeAiDiagram(result.diagram, database);
// after
const raw = result?.diagram;
if (!raw || !Array.isArray(raw.tables) || raw.tables.length === 0) {
setError({ type: STATUS.ERROR, message: "AI returned no tables. Refine the input and try again." });
return;
}
const { diagram, warnings } = normalizeAiDiagram(raw, database); Defensive patterns
Strategy: validation
Validate before calling
// Run this BEFORE normalizeAiDiagram to guarantee the precondition.
function hasAiTables(raw) {
return (
!!raw &&
typeof raw === "object" &&
Array.isArray(raw.tables) &&
raw.tables.length > 0
);
}
// In importSourceWithAi (Modal.jsx) before line 203:
const raw = result?.diagram;
if (!hasAiTables(raw)) {
setError({
type: STATUS.ERROR,
message: "The AI service returned no tables. Refine the input and retry.",
});
return;
}
const { diagram, warnings } = normalizeAiDiagram(raw, database); Type guard
// JSDoc-narrowed predicate (plain JS; works as a TS guard if you adopt TS).
/**
* @param {unknown} raw
* @returns {raw is { tables: unknown[]; enums?: unknown[]; types?: unknown[]; relationships?: unknown[] }}
*/
function isAiDiagramPayload(raw) {
if (!raw || typeof raw !== "object") return false;
const tables = /** @type {any} */ (raw).tables;
return Array.isArray(tables) && tables.length > 0;
} Try / catch
// Keep the existing try/catch in importSourceWithAi, but branch on this message
// so a missing-tables payload is reported cleanly instead of leaking the generic error.
try {
const { diagram, warnings } = normalizeAiDiagram(result.diagram, database);
// ...applyImportedDiagram(diagram)...
} catch (e) {
if (e?.message === "The AI import returned no tables.") {
setError({
type: STATUS.ERROR,
message: "The AI produced no tables. Adjust the prompt/SQL and try again.",
});
return;
}
throw e; // unknown error — let the outer handler decide
} Prevention
- Always log the shape of `result.diagram` (Object.keys + tables.length) in dev builds before invoking normalizeAiDiagram.
- Treat the AI service contract as `{ tables: Array, ... }` and assert it at the boundary in importSqlWithAi, not at the UI.
- Retry once on an empty payload before surfacing a hard error — empty bodies are frequently transient.
- Pin the AI prompt to require a non-empty `tables` array and include a one-shot example of the minimal object.
When it happens
Trigger: Calling `normalizeAiDiagram(raw, database)` where (a) `raw` is null/undefined, (b) `raw.tables` is missing or not an array (e.g. an object, a string, a number), or (c) `raw.tables` is an array of length 0. In the app this is reached via Modal.jsx:203 as `normalizeAiDiagram(result.diagram, database)` after `importSqlWithAi(...)`, so any AI service response whose body lacks a populated `tables` field triggers it.
Common situations: The AI endpoint returned 200 but with an empty/malformed JSON body (e.g. `{}` or `{ "error": "..." }`); the model returned prose or a markdown code fence instead of a table array; an upstream JSON.parse collapsed the payload to null; the model hit a token/quota limit and emitted a truncated object; the import prompt was changed and no longer asks for a `tables` array; a retry returned a cached empty degenerate response.
Related errors
AI-assisted analysis of drawdb-io/drawdb@e7086e7fc2 (2026-08-13).
Data as JSON: /api/errors/683a5a7f87593d72.
Report an issue: GitHub.