{"record":{"id":"78b4d031502fd76d","repo":"hasura/graphql-engine","slug":"encountered-a-non-statement-or-non-list-ddl-for-ta","errorCode":null,"errorMessage":"Encountered a non-statement or non-list DDL for table.","messagePattern":"Encountered a non-statement or non-list DDL for table\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"dc-agents/sqlite/src/schema.ts","lineNumber":227,"sourceCode":" *     },\n *     foreign_table: \"Artist\",\n *   }\n * }\n *\n * NOTE: We currently don't log if the structure of the DDL is unexpected, which could be the case for composite FKs, etc.\n * NOTE: There could be multiple paths between tables.\n * NOTE: Composite keys are not currently supported.\n *\n * @param ddl\n * @returns [name, FK constraint definition][]\n */\nfunction ddlFKs(\n  config: Config,\n  tableName: Array<string>,\n  ddl: any,\n): [string, Constraint][] {\n  if (ddl.type != 'statement' || ddl.variant != 'list') {\n    throw new Error('Encountered a non-statement or non-list DDL for table.');\n  }\n  return ddl.statement.flatMap((t: any) => {\n    if (t.type != 'statement' || t.variant != 'create' || t.format != 'table') {\n      return [];\n    }\n    return t.definition.flatMap((c: any) => {\n      if (\n        c.type != 'definition' ||\n        c.variant != 'constraint' ||\n        c.definition.length != 1 ||\n        c.definition[0].type != 'constraint' ||\n        c.definition[0].variant != 'foreign key'\n      ) {\n        return [];\n      }\n      if (c.columns.length != 1) {\n        return [];\n      }","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/dc-agents/sqlite/src/schema.ts#L209-L245","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run the agent with logging to identify which table's DDL fails, then simplify that table's DDL","Verify every introspected table has valid plain CREATE TABLE DDL in sqlite_master","Pin the sqlite-parser version that matches your SQLite dialect and file an issue with the failing DDL"],"exampleFix":"-- before: FK syntax the parser mishandles\nCREATE TABLE t (a INT, FOREIGN KEY(a) REFERENCES p(x) DEFERRABLE INITIALLY DEFERRED);\n-- after\nCREATE TABLE t (a INT REFERENCES p(x));","handlingStrategy":"try-catch","validationCode":"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));","typeGuard":"const hasPlainCreateTable = (row: {sql: string|null}): row is {sql: string} => !!row.sql && row.sql.toUpperCase().startsWith('CREATE TABLE');","tryCatchPattern":"try { await introspectFks(table); } catch (e) { if (/non-statement or non-list/.test(String(e))) log.warn(`FK introspection failed for ${table}`); }","preventionTips":["Avoid exotic DDL (deferred FKs, WITHOUT ROWID quirks) in tables the agent introspects","Test schema introspection in CI against your actual DB file","Match sqlite-parser and SQLite versions"],"tags":["sqlite","ddl","parser","foreign-keys","schema-introspection"],"backgroundTag":"ddl-parse-failure","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}