hasura/graphql-engine · error · Error

Encountered a non-statement or non-list DDL for table.

Error message

Encountered a non-statement or non-list DDL for table.

What it means

Same AST shape check as getColumnsDdl, applied when extracting FOREIGN KEY constraints from parsed DDL (ddlFKs, feeding the foreignKeys flow). If sqlite-parser's output for a table's DDL is not a statement list, FK introspection aborts with this error, which usually kills the whole schema request.

Source

Thrown at dc-agents/sqlite/src/schema.ts:227

 *     },
 *     foreign_table: "Artist",
 *   }
 * }
 *
 * NOTE: We currently don't log if the structure of the DDL is unexpected, which could be the case for composite FKs, etc.
 * NOTE: There could be multiple paths between tables.
 * NOTE: Composite keys are not currently supported.
 *
 * @param ddl
 * @returns [name, FK constraint definition][]
 */
function ddlFKs(
  config: Config,
  tableName: Array<string>,
  ddl: any,
): [string, Constraint][] {
  if (ddl.type != 'statement' || ddl.variant != 'list') {
    throw new Error('Encountered a non-statement or non-list DDL for table.');
  }
  return ddl.statement.flatMap((t: any) => {
    if (t.type != 'statement' || t.variant != 'create' || t.format != 'table') {
      return [];
    }
    return t.definition.flatMap((c: any) => {
      if (
        c.type != 'definition' ||
        c.variant != 'constraint' ||
        c.definition.length != 1 ||
        c.definition[0].type != 'constraint' ||
        c.definition[0].variant != 'foreign key'
      ) {
        return [];
      }
      if (c.columns.length != 1) {
        return [];
      }

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Run the agent with logging to identify which table's DDL fails, then simplify that table's DDL
  2. Verify every introspected table has valid plain CREATE TABLE DDL in sqlite_master
  3. Pin the sqlite-parser version that matches your SQLite dialect and file an issue with the failing DDL

Example fix

-- before: FK syntax the parser mishandles
CREATE TABLE t (a INT, FOREIGN KEY(a) REFERENCES p(x) DEFERRABLE INITIALLY DEFERRED);
-- after
CREATE TABLE t (a INT REFERENCES p(x));
Defensive patterns

Strategy: try-catch

Validate before calling

const bad = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND (sql IS NULL OR upper(sql) NOT LIKE 'CREATE TABLE%')").all(); if (bad.length) throw new Error('Tables with non-standard DDL: ' + bad.map(r=>r.name));

Type guard

const hasPlainCreateTable = (row: {sql: string|null}): row is {sql: string} => !!row.sql && row.sql.toUpperCase().startsWith('CREATE TABLE');

Try / catch

try { await introspectFks(table); } catch (e) { if (/non-statement or non-list/.test(String(e))) log.warn(`FK introspection failed for ${table}`); }

Prevention

When it happens

Trigger: Schema introspection hitting a table whose DDL parses to an unexpected node — malformed CREATE TABLE, DDL stored as NULL, parser/SQLite version mismatch, or CREATE TABLE with inline REFERENCES clauses the parser mishandles.

Common situations: Databases with unusual DDL (WITHOUT ROWID, DEFERRABLE FKs, generated columns); sqlite-parser upgrades changing AST structure; migrating a DB dumped by a different SQLite version.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/78b4d031502fd76d. Report an issue: GitHub.