{"record":{"id":"9fc40f40e955e5f2","repo":"can1357/oh-my-pi","slug":"sqlite-order-column-column-not-found-in-table","errorCode":null,"errorMessage":"SQLite order column '${column}' not found in table schema","messagePattern":"SQLite order column '(.+?)' not found in table schema","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/sqlite-reader.ts","lineNumber":387,"sourceCode":"\treturn key;\n}\n\nfunction resolveOrderClause(order: string | undefined, columns: string[]): string {\n\tif (!order) return \"\";\n\tconst trimmed = order.trim();\n\tif (!trimmed) return \"\";\n\n\tconst separatorIndex = trimmed.lastIndexOf(\":\");\n\tconst column = separatorIndex === -1 ? trimmed : trimmed.slice(0, separatorIndex);\n\tconst direction =\n\t\tseparatorIndex === -1\n\t\t\t? \"asc\"\n\t\t\t: trimmed\n\t\t\t\t\t.slice(separatorIndex + 1)\n\t\t\t\t\t.trim()\n\t\t\t\t\t.toLowerCase();\n\tif (!columns.includes(column)) {\n\t\tthrow new ToolError(`SQLite order column '${column}' not found in table schema`);\n\t}\n\tif (direction !== \"asc\" && direction !== \"desc\") {\n\t\tthrow new ToolError(`SQLite order direction must be 'asc' or 'desc'; got '${direction}'`);\n\t}\n\treturn ` ORDER BY ${quoteSqliteIdentifier(column)} ${direction.toUpperCase()}`;\n}\n\nconst FORBIDDEN_WHERE_KEYWORDS = new Set([\n\t\"limit\",\n\t\"offset\",\n\t\"union\",\n\t\"intersect\",\n\t\"except\",\n\t\"attach\",\n\t\"detach\",\n\t\"pragma\",\n]);\n","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/sqlite-reader.ts#L369-L405","documentation":"Thrown by resolveOrderClause in the sqlite-reader tool when the 'order' query parameter names a column that does not exist in the target table's schema. The tool validates ORDER BY columns against the actual table columns to prevent SQL injection and confusing SQLite errors, since only schema-known identifiers are quoted and accepted.","triggerScenarios":"Calling the sqlite read tool with an order param like 'table:users?order=email:asc' where 'email' is not a column of the users table; renaming a column without updating the order param; typos or case mismatches in the column name.","commonSituations":"Schema drift after a migration added/renamed columns; hard-coded order fields copied from another table; assuming SQLite column names are case-insensitive when the schema check is exact-match.","solutions":["Inspect the table schema (e.g. PRAGMA table_info or a schema-listing call) and use an existing column name","Fix typos/case in the order parameter to match the schema exactly","Remove the order param to get default row ordering","If the column was renamed in a migration, update the calling code to the new name"],"exampleFix":"// before\ntool.read('sqlite:users?order=emial:asc')\n// after\ntool.read('sqlite:users?order=email:asc')","handlingStrategy":"validation","validationCode":"const cols = await listTableColumns('users');\nif (orderColumn && !cols.includes(orderColumn)) {\n  throw new Error(`order column '${orderColumn}' not in [${cols.join(', ')}]`);\n}","typeGuard":"function isValidOrderColumn(col: string, columns: string[]): col is string {\n  return columns.includes(col);\n}","tryCatchPattern":"try {\n  await reader.read(`db.sqlite/users?order=${col}:asc`);\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes(\"not found in table schema\")) {\n    // fall back to default ordering or log schema mismatch\n  } else throw err;\n}","preventionTips":["Fetch the table schema before constructing order params","Derive order columns from schema metadata, not hard-coded strings","Add a unit test asserting order params against the live schema"],"tags":["sqlite","validation","sql-injection-guard"],"backgroundTag":"unknown-column-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}