drawdb-io/drawdb · error · Error
The AI import produced a diagram we could not read. Please t
Error message
The AI import produced a diagram we could not read. Please try again.
What it means
Thrown after normalization when the assembled diagram fails `jsonDiagramIsValid`, which runs the `jsonschema` Validator against `jsonSchema` (src/data/schemas.js). It means the AI payload had a non-empty `tables` array but the normalized shape still violates the JSON Schema contract — required table keys (id, name, x, y, fields, comment, indices, color), required field keys (id, name, type, default, check, primary, unique, notNull, increment, comment), the `^#[0-9a-fA-F]{6}$` color pattern, or required relationship keys. The single source site is src/utils/importAiDiagram.js:108.
Source
Thrown at src/utils/importAiDiagram.js:109
warnings.push(
`Skipped relationship "${relationship.name}" because it did not resolve to a column.`,
);
}
return resolves;
});
const diagram = {
tables,
relationships: relationships.map((relationship, id) => ({
...relationship,
id,
})),
enums,
types,
};
if (!jsonDiagramIsValid({ ...diagram, notes: [], subjectAreas: [] })) {
throw new Error(
"The AI import produced a diagram we could not read. Please try again.",
);
}
arrangeTables(diagram);
return { diagram, warnings };
}
View on GitHub (pinned to e7086e7fc2)
Solutions
- Capture `new Validator().validate(obj, jsonSchema).errors` and log it — it lists every offending property so you know exactly which required key or pattern failed.
- Default-fill every schema-required key when mapping `raw.tables` and each `field` (the current mapping at lines 73-80 only reassigns `type`); enrich `raw` before calling normalizeAiDiagram or extend the mapping inside it.
- Update the AI system prompt to include the exact JSON Schema (or a minimal required-keys example) so the model emits `comment`, `indices`, `color`, and full field objects.
- Coerce types defensively: `Number(table.x ?? 0)`, `String(field.comment ?? "")`, and a hex fallback for `color`.
- Pin the `jsonschema` package version and review `src/data/schemas.js` required arrays after any change — new required keys retroactively break existing AI output.
Example fix
// before (src/utils/importAiDiagram.js:73-80) — only reassigns type, leaves required keys un-filled
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 };
}),
}));
// after — default-fill every schema-required table/field key
const HEX = /^#[0-9a-fA-F]{6}$/;
const tables = raw.tables.map((table) => ({
id: table.id ?? table.name,
name: String(table.name ?? "Untitled"),
x: Number(table.x ?? 0),
y: Number(table.y ?? 0),
comment: table.comment ?? "",
indices: table.indices ?? [],
color: HEX.test(table.color) ? table.color : "#175e7a",
...table,
fields: (table.fields ?? []).map((field) => {
const { type, warning } = resolveType(field.type, validTypes, declaredNames);
if (warning) warnings.push(warning);
return {
id: field.id ?? field.name,
name: String(field.name ?? "field"),
default: field.default ?? "",
check: field.check ?? "",
primary: field.primary ?? false,
unique: field.unique ?? false,
notNull: field.notNull ?? false,
increment: field.increment ?? false,
comment: field.comment ?? "",
...field,
type,
};
}),
})); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-fill every schema-required key on each table/field so jsonDiagramIsValid passes.
// Apply this to raw.tables BEFORE calling normalizeAiDiagram (or fold it into the mapping).
import { jsonDiagramIsValid } from "../utils/validateSchema";
const HEX = /^#[0-9a-fA-F]{6}$/;
function normalizeTableShape(table) {
return {
id: table.id ?? table.name,
name: String(table.name ?? "Untitled"),
x: Number(table.x ?? 0),
y: Number(table.y ?? 0),
comment: table.comment ?? "",
indices: Array.isArray(table.indices) ? table.indices : [],
color: HEX.test(table.color) ? table.color : "#175e7a",
...table,
fields: (table.fields ?? []).map((f) => ({
id: f.id ?? f.name,
name: String(f.name ?? "field"),
default: f.default ?? "",
check: f.check ?? "",
primary: f.primary ?? false,
unique: f.unique ?? false,
notNull: f.notNull ?? false,
increment: f.increment ?? false,
comment: f.comment ?? "",
...f,
})),
};
}
// Usage:
const enriched = { ...result.diagram, tables: (result.diagram.tables ?? []).map(normalizeTableShape) };
const probe = { tables: enriched.tables, relationships: [], notes: [], subjectAreas: [], enums: [], types: [] };
if (!jsonDiagramIsValid(probe)) {
// still invalid — surface a precise error instead of letting normalizeAiDiagram throw blindly
setError({ type: STATUS.ERROR, message: "AI diagram shape rejected by schema." });
return;
}
const { diagram, warnings } = normalizeAiDiagram(enriched, database); Type guard
// Narrow a single table to the jsonSchema `tableSchema` required-key set.
const TABLE_REQUIRED = ["id", "name", "x", "y", "fields", "comment", "indices", "color"];
const FIELD_REQUIRED = ["id", "name", "type", "default", "check", "primary", "unique", "notNull", "increment", "comment"];
/**
* @param {unknown} t
* @returns {t is Record<string, unknown>}
*/
function tableMeetsSchema(t) {
if (!t || typeof t !== "object") return false;
const table = /** @type {any} */ (t);
if (!TABLE_REQUIRED.every((k) => Object.prototype.hasOwnProperty.call(table, k))) return false;
if (typeof table.x !== "number" || typeof table.y !== "number") return false;
if (!/^#[0-9a-fA-F]{6}$/.test(table.color)) return false;
return Array.isArray(table.fields) && table.fields.every((f) =>
FIELD_REQUIRED.every((k) => Object.prototype.hasOwnProperty.call(f, k))
);
} Try / catch
// Re-validate inside catch to extract the precise schema violations for diagnostics.
import { Validator } from "jsonschema";
import { jsonSchema } from "../data/schemas";
try {
const { diagram, warnings } = normalizeAiDiagram(raw, database);
// ...use diagram...
} catch (e) {
if (e?.message?.startsWith("The AI import produced a diagram")) {
const probe = { tables: raw.tables, relationships: raw.relationships ?? [], notes: [], subjectAreas: [], enums: raw.enums ?? [], types: raw.types ?? [] };
const result = new Validator().validate(probe, jsonSchema);
// result.errors is an array of { property, message, schema, argument }
console.error("AI diagram schema failures:", result.errors);
setError({
type: STATUS.ERROR,
message: "Could not read AI diagram. See console for the failing schema keys.",
});
return;
}
throw e;
} Prevention
- Default-fill every required key (including empty-string `comment`/`check`/`default` and `[]` for `indices`) when mapping AI output — LLMs routinely omit empty-valued keys.
- On failure, log `new Validator().validate(obj, jsonSchema).errors` to identify the exact offending property instead of guessing.
- Treat `src/data/schemas.js` `required` arrays as a breaking contract: review every AI prompt after adding a required key.
- Pin the `jsonschema` package version; stricter coercion in newer versions can flip a previously-valid diagram to invalid.
- Add unit tests for normalizeAiDiagram against minimal fixtures (table with only id/name/fields) so schema regressions surface in CI, not in production.
When it happens
Trigger: Any of: a table in `raw.tables` is missing `id`/`name`/`x`/`y`/`comment`/`indices`/`color`; `x`/`y` are non-numeric; `color` is absent or not a 6-digit hex; a field is missing `default`/`check`/`primary`/`unique`/`notNull`/`increment`/`comment`; a relationship is missing `startTableId`/`startFieldId`/`endTableId`/`endFieldId`/`name`/`cardinality`/`updateConstraint`/`deleteConstraint`. Note the table/field mapping at src/utils/importAiDiagram.js:73-80 only re-spreads each object and reassigns `type` — it does not default-fill the schema-required keys, so any AI omission flows straight into the validator.
Common situations: The AI omitted empty-string fields like `comment`/`check`/`default` (LLMs frequently drop keys whose value is empty); the AI returned tables without positional `x`/`y`; the AI omitted `indices` or `color`; a schema migration added a new required key (e.g. `uniqueConstraints`) that older prompts don't emit; a jsonschema version bump enforces stricter coercion (numbers vs numeric strings); the AI enumerated fields as a plain array of strings instead of objects.
Related errors
AI-assisted analysis of drawdb-io/drawdb@e7086e7fc2 (2026-08-13).
Data as JSON: /api/errors/71e2d8d4b855a855.
Report an issue: GitHub.