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

  1. 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.
  2. 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.
  3. 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.
  4. Coerce types defensively: `Number(table.x ?? 0)`, `String(field.comment ?? "")`, and a hex fallback for `color`.
  5. 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

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.