{"record":{"id":"33d4d7eb6486279c","repo":"can1357/oh-my-pi","slug":"sqlite-table-table-has-no-column-named-col","errorCode":null,"errorMessage":"SQLite table '${table}' has no column named '${column}'","messagePattern":"SQLite table '(.+?)' has no column named '(.+?)'","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/sqlite-reader.ts","lineNumber":522,"sourceCode":"\t\ttypeof value === \"string\" ||\n\t\ttypeof value === \"number\" ||\n\t\ttypeof value === \"boolean\" ||\n\t\ttypeof value === \"bigint\"\n\t) {\n\t\treturn value;\n\t}\n\tthrow new ToolError(`SQLite column '${column}' only accepts JSON scalar values or null`);\n}\n\nfunction validateWriteColumns(\n\tdb: Database,\n\ttable: string,\n\tdata: Record<string, unknown>,\n): Array<[string, SqliteBinding]> {\n\tconst columns = new Set(getTableColumns(db, table));\n\treturn Object.entries(data).map(([column, value]) => {\n\t\tif (!columns.has(column)) {\n\t\t\tthrow new ToolError(`SQLite table '${table}' has no column named '${column}'`);\n\t\t}\n\t\treturn [column, normalizeWriteValue(value, column)];\n\t});\n}\n\nexport function parseSqlitePathCandidates(filePath: string): SqlitePathCandidate[] {\n\tconst normalized = filePath.replace(/\\\\/g, \"/\");\n\tconst seen = new Set<string>();\n\tconst candidates: SqlitePathCandidate[] = [];\n\n\tlet match: RegExpExecArray | null;\n\twhile (true) {\n\t\tmatch = SQLITE_PATH_PATTERN.exec(normalized);\n\t\tif (match === null) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst end = match.index + match[0].length;","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/sqlite-reader.ts#L504-L540","documentation":"Thrown by validateWriteColumns when the data object contains a key that is not a column of the target table. Every write key is checked against getTableColumns(db, table) before any binding is built, protecting against silently failed or SQL-erroring writes.","triggerScenarios":"write('users', { usernane: 'x' }) — typo; writing fields removed/renamed by a recent migration; including extra payload fields (e.g. id in an insert where the column doesn't exist); writing to the wrong table.","commonSituations":"Schema drift after migrations; API payloads passed straight through to the writer; case mismatches between payload keys and actual column names.","solutions":["Inspect the table schema and align data keys to actual column names","Fix typos in the data object keys","Remove fields that don't exist in the table or map them to existing columns","After migrations, update the write payload to the new column names"],"exampleFix":"// before\nwrite('users', { usernane: 'bob' })\n// after\nwrite('users', { username: 'bob' })","handlingStrategy":"validation","validationCode":"const cols = new Set(await listTableColumns(table));\nconst bad = Object.keys(data).filter(k => !cols.has(k));\nif (bad.length) throw new Error(`unknown columns for '${table}': ${bad.join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  await writer.write('users', data);\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes('has no column named')) {\n    // refresh schema, drop unknown keys, and retry\n  } else throw err;\n}","preventionTips":["Validate payload keys against PRAGMA table_info before writes","Never pass raw API payloads straight through — map to explicit columns","Re-check writes after any schema migration"],"tags":["sqlite","validation","schema","write"],"backgroundTag":"unknown-column-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}