{"record":{"id":"04974f1efa6dd8dc","repo":"hasura/graphql-engine","slug":"encountered-a-non-statement-or-non-list-when-parsi","errorCode":null,"errorMessage":"Encountered a non-statement or non-list when parsing DDL for table.","messagePattern":"Encountered a non-statement or non-list when parsing DDL for table\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"dc-agents/sqlite/src/schema.ts","lineNumber":185,"sourceCode":"          .concat(filterForOnlyTheseTables ?? [])\n          .indexOf(table.name) >= 0\n      );\n    } else {\n      return true;\n    }\n  };\n\n/**\n * Pulls columns from the output of sqlite-parser.\n * Note that this doesn't check if duplicates are present and will emit them as many times as they are present.\n * This is done as an easy way to preserve order.\n *\n * @param ddl - The output of sqlite-parser\n * @returns - List of columns as present in the output of sqlite-parser.\n */\nfunction getColumnsDdl(ddl: any): any[] {\n  if (ddl.type != 'statement' || ddl.variant != 'list') {\n    throw new Error(\n      'Encountered a non-statement or non-list when parsing DDL for table.',\n    );\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 (c.type != 'definition' || c.variant != 'column') {\n        return [];\n      }\n      return [c];\n    });\n  });\n}\n\n/**\n * Example:","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/dc-agents/sqlite/src/schema.ts#L167-L203","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Inspect `SELECT name, sql FROM sqlite_master WHERE type='table'` for NULL or unusual DDL and drop/fix those tables","Pin or upgrade the sqlite-parser dependency to match the SQLite version in use","Clean stray internal tables (sqlite_sequence-like, shadow tables of FTS) that the agent tries to introspect"],"exampleFix":"-- before: ghost table with NULL sql\nCREATE VIRTUAL TABLE t USING fts5(a);\n-- after: exclude virtual/shadow tables or ensure introspected tables have plain CREATE TABLE DDL","handlingStrategy":"try-catch","validationCode":"const rows = db.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND sql IS NOT NULL\").all(); // only expose tables with parseable DDL","typeGuard":"const hasCreateTableDdl = (row: {sql: string|null}): row is {sql: string} => typeof row.sql === 'string' && /^CREATE\\s+TABLE/i.test(row.sql);","tryCatchPattern":"try { await agent.getSchema(); } catch (e) { if (/non-statement or non-list/.test(String(e))) { await auditSqliteMasterDdl(); throw e; } }","preventionTips":["Audit sqlite_master DDL before pointing the agent at a DB","Keep virtual/shadow tables out of the introspected set","Pin sqlite-parser compatible with your SQLite version"],"tags":["sqlite","ddl","parser","schema-introspection"],"backgroundTag":"ddl-parse-failure","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}