{"record":{"id":"309d106760d34cce","repo":"tirth8205/code-review-graph","slug":"unknown-table-table","errorCode":null,"errorMessage":"Unknown table: {table}","messagePattern":"Unknown table: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"code_review_graph/migrations.py","lineNumber":51,"sourceCode":"\ndef _set_schema_version(conn: sqlite3.Connection, version: int) -> None:\n    \"\"\"Set the schema version in the metadata table.\"\"\"\n    conn.execute(\n        \"INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', ?)\",\n        (str(version),),\n    )\n\n\n_KNOWN_TABLES = frozenset({\n    \"nodes\", \"edges\", \"metadata\", \"communities\", \"flows\", \"flow_memberships\", \"nodes_fts\",\n    \"community_summaries\", \"flow_snapshots\", \"risk_index\",\n})\n\n\ndef _has_column(conn: sqlite3.Connection, table: str, column: str) -> bool:\n    \"\"\"Check if a column exists in a table.\"\"\"\n    if table not in _KNOWN_TABLES:\n        raise ValueError(f\"Unknown table: {table}\")\n    cursor = conn.execute(f\"PRAGMA table_info({table})\")  # noqa: S608\n    columns = [row[1] if isinstance(row, tuple) else row[\"name\"] for row in cursor]\n    return column in columns\n\n\ndef _table_exists(conn: sqlite3.Connection, table: str) -> bool:\n    \"\"\"Check if a table exists.\"\"\"\n    if table not in _KNOWN_TABLES:\n        raise ValueError(f\"Unknown table: {table}\")\n    row = conn.execute(\n        \"SELECT count(*) FROM sqlite_master WHERE type IN ('table', 'view') \"\n        \"AND name = ?\",\n        (table,),\n    ).fetchone()\n    return row[0] > 0\n\n\n# ---------------------------------------------------------------------------","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/tirth8205/code-review-graph/blob/b58668751ab0c7670c078cf7cbd4d1f5b8e54f81/code_review_graph/migrations.py#L33-L69","documentation":"_has_column() only accepts tables listed in the _KNOWN_TABLES whitelist before running PRAGMA table_info, raising ValueError for anything else. This guards migrations against typos and SQL injection via the interpolated table name.","triggerScenarios":"A migration (e.g. _migrate_v2, _migrate_v4, _migrate_v9) calls _has_column with a table name that is not in _KNOWN_TABLES — typically after a schema change adds a new table without updating the whitelist, or an internal call passes a renamed table.","commonSituations":"Contributors adding new tables to the schema in a new migration but forgetting to register them in _KNOWN_TABLES; refactors renaming tables; version skew between migration code and the whitelist constant.","solutions":["Add the new table name to the _KNOWN_TABLES set in code_review_graph/migrations.py.","Verify the spelling/case matches exactly (SQLite PRAGMA lookups are case-insensitive but the whitelist check is not).","If hitting this as a library user on an old version after a schema change, upgrade the package so the whitelist matches the migrations."],"exampleFix":"# before\n_KNOWN_TABLES = {\"nodes\", \"edges\"}\n_has_column(conn, \"symbols\", \"kind\")\n# after\n_KNOWN_TABLES = {\"nodes\", \"edges\", \"symbols\"}\n_has_column(conn, \"symbols\", \"kind\")","handlingStrategy":"validation","validationCode":"from code_review_graph.migrations import _KNOWN_TABLES\nif table not in _KNOWN_TABLES:\n    raise ValueError(f\"register {table!r} in _KNOWN_TABLES before probing columns\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep _KNOWN_TABLES adjacent to schema definitions so both change together.","Add a test that iterates every table used by migrations and asserts whitelist membership.","Use case-exact table names matching CREATE TABLE statements."],"tags":["sqlite","migration","schema","internal"],"backgroundTag":"schema-validation-failed","analyzedSha":"b58668751ab0c7670c078cf7cbd4d1f5b8e54f81","analyzedAt":"2026-08-28T13:19:08.966Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}