hasura/graphql-engine · error · Error

Encountered a non-statement or non-list when parsing DDL for

Error message

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

What it means

The SQLite agent introspects table DDL by running it through sqlite-parser. getColumnsDdl expects the parse result to be a `{type:'statement', variant:'list'}` node; anything else (unexpected parser output, empty/malformed DDL, or a parser version producing a different AST shape) throws this error during column introspection for the columnsDdl flow.

Source

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

          .concat(filterForOnlyTheseTables ?? [])
          .indexOf(table.name) >= 0
      );
    } else {
      return true;
    }
  };

/**
 * Pulls columns from the output of sqlite-parser.
 * Note that this doesn't check if duplicates are present and will emit them as many times as they are present.
 * This is done as an easy way to preserve order.
 *
 * @param ddl - The output of sqlite-parser
 * @returns - List of columns as present in the output of sqlite-parser.
 */
function getColumnsDdl(ddl: any): any[] {
  if (ddl.type != 'statement' || ddl.variant != 'list') {
    throw new Error(
      'Encountered a non-statement or non-list when parsing 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 != 'column') {
        return [];
      }
      return [c];
    });
  });
}

/**
 * Example:

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Inspect `SELECT name, sql FROM sqlite_master WHERE type='table'` for NULL or unusual DDL and drop/fix those tables
  2. Pin or upgrade the sqlite-parser dependency to match the SQLite version in use
  3. Clean stray internal tables (sqlite_sequence-like, shadow tables of FTS) that the agent tries to introspect

Example fix

-- before: ghost table with NULL sql
CREATE VIRTUAL TABLE t USING fts5(a);
-- after: exclude virtual/shadow tables or ensure introspected tables have plain CREATE TABLE DDL
Defensive patterns

Strategy: try-catch

Validate before calling

const rows = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND sql IS NOT NULL").all(); // only expose tables with parseable DDL

Type guard

const hasCreateTableDdl = (row: {sql: string|null}): row is {sql: string} => typeof row.sql === 'string' && /^CREATE\s+TABLE/i.test(row.sql);

Try / catch

try { await agent.getSchema(); } catch (e) { if (/non-statement or non-list/.test(String(e))) { await auditSqliteMasterDdl(); throw e; } }

Prevention

When it happens

Trigger: Calling schema introspection when a table's `sqlite_master.sql` DDL is NULL (e.g. some internal/ghost tables), malformed, or uses syntax sqlite-parser can't handle (generated columns, new SQLite features, WITHOUT ROWID edge cases).

Common situations: Upgrading SQLite or the sqlite-parser dependency so AST shapes change; databases containing virtual tables, shadow tables, or views with the same name; DDL containing constructs the old parser rejects.

Related errors


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