AI + Analytics

How We Keep an LLM From Inventing a Column Name

By Chinmay Raibagkar·August 28, 2026·11 min read·Deep dive

The 60-second version

A model that has never seen your schema will guess `order_total` and be wrong. The four layers — retrieval, constrained context, dry-run validation, repair — that stop it shipping.

  • What happened, in one line
  • What to do about it this week
  • What you can safely ignore

Ask a language model for "total revenue by campaign last month" and, with no knowledge of your schema, it will write something confident:

SELECT campaign_name, SUM(revenue) AS total_revenue
FROM orders
WHERE order_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH)
GROUP BY campaign_name;

Reasonable-looking, and wrong in four ways at once. Your table is sales_orders. There is no revenue column — there is net_total. There is no campaign_name on an order at all. And order_date is created_at, a timestamp, not a date.

This is not a model being bad. It is a model doing exactly what it was asked with information it did not have. The fix is four layers of engineering, and none of them is "use a better model."


Why it happens

A language model generates the most plausible continuation given its context. Trained on a great deal of public SQL, its prior for an orders table is order_id, customer_id, order_date, revenue, status — because that is what most published example schemas look like.

If your actual schema is not in the context window, the model does not know it is guessing. There is no internal signal distinguishing "I recall this column exists" from "this is the most likely column name for a table like this." Both produce the same confident output.

The reframe that makes this tractable: hallucination here is not a reasoning failure, it is a retrieval failure. The model was asked to write SQL against a schema it could not see. Fix the retrieval and most of the problem disappears — which is why this is an engineering problem with a known solution, rather than a fundamental limit like establishing causation.


The four layers

Defence in Depth

Process Flow
1

Retrieval — put the real schema in context

Fetch actual table and column names, types, modes and descriptions from the warehouse. The model cannot invent what it has been given.

2

Constraint — give it only what is relevant

Twelve relevant tables beat two hundred. Too much schema is as harmful as too little, for different reasons.

3

Validation — dry-run before executing

A dry run parses the SQL against the real schema and fails on any invalid column, for free, in under a second. This is the layer that catches everything the first two missed.

4

Repair — feed the error back and retry

A validation error naming the bad column is an excellent correction signal. One retry loop resolves the large majority of remaining failures.

Layer 1: Retrieval

Fetch the real schema from the warehouse and put it in context. BigQuery's table metadata gives you name, type, mode, and — critically — description:

Schema Retrieval Straight From INFORMATION_SCHEMA

Show query

Column descriptions are the highest-return investment here, and nobody makes it. A description reading 'Order total INCLUDING tax and shipping — do not use for revenue reporting, use net_total' prevents a wrong answer that no amount of model capability would have caught. It lives in the warehouse, so every tool sees it, and it takes about an hour to write for your twenty most-queried tables.

Layer 2: Constraint

More schema is not better. Two hundred tables in context creates three problems: the relevant one competes for attention with 199 others, the cost per question rises with every token, and long contexts degrade instruction-following.

Selection strategies, in ascending order of effort:

  • Curated allowlist — expose only the semantic schema, not raw tables. Crude, extremely effective, and it doubles as a semantic layer.
  • Keyword and lexical matching — question mentions "campaign", so include tables whose names or columns contain campaign-ish terms.
  • Embedding retrieval — embed table descriptions, retrieve the top N by similarity to the question. Scales to hundreds of tables.
  • Two-pass selection — a first cheap call picks the tables from a list of names and one-line descriptions; a second call gets full schemas for only those.

The two-pass approach is usually the best cost-to-quality trade above about fifty tables: the first pass is short and cheap, and the second gets a small, highly relevant context.

Same question, three retrieval strategies

Why constraint matters
No schemaInvents plausible columnsFails validation, or worse, accidentally matches a real column that means something else
All 200 tablesCorrect but expensiveLarge token cost per question; picks a deprecated table roughly as often as the current one
Top 8, retrievedCorrect and cheapSmall context, high signal, right table chosen because the wrong ones were not offered
Semantic views onlyCorrect and unambiguousThe ambiguous raw columns are not reachable, so they cannot be picked
The failure mode of too much schema is subtler than too little: the query is valid and runs, but against orders_v1 rather than orders, because both were offered and nothing said which was current. A validator cannot catch that — only constraint can.

Layer 3: Validation

This is the layer that turns a probabilistic system into a safe one, and it is remarkably cheap.

A dry run parses and plans the query against the real schema without executing it. It returns either an error naming the exact problem, or the byte estimate. It costs nothing and takes under a second.

POST /bigquery/v2/projects/{projectId}/queries
{ "query": "<generated sql>", "dryRun": true, "useLegacySql": false }

Two things come back that matter:

  • Any schema errorUnrecognized name: revenue at [1:24]. The query never ran, nothing was billed, and you have a precise error.
  • totalBytesProcessed — what it would cost. Which lets you enforce a ceiling before execution rather than discovering it on an invoice.

DataLens runs this on every generated query before execution, and passes maximumBytesBilled on the real run as a second belt: even if the estimate were somehow wrong, the query fails rather than billing beyond the cap.

Validation is not optional and it is not expensive. Any tool generating SQL against a warehouse can dry-run it for free, in under a second, before showing you anything. A tool that executes generated SQL without validating it first is choosing not to do the cheapest safety step available.

Layer 4: Repair

A validation error is an unusually good correction signal, because it is specific: it names the offending identifier and its position.

The Repair Loop

Process Flow
1

Dry run fails with a named identifier

'Unrecognized name: revenue at [1:24]. Did you mean revenue_net?' — BigQuery often suggests the nearest match itself.

2

Feed the error back with the schema

Return the exact error text plus the columns of the tables involved. Do not paraphrase the error; the literal text is the most useful part.

3

Regenerate and re-validate

The corrected query goes through the same dry run. No special-casing — the same gate every time.

4

Cap the retries, then ask the human

Two attempts. If it still fails, the problem is usually ambiguity in the question rather than in the SQL, and another retry will not find it.

Capping retries matters. A loop that retries five times burns tokens working around a question that cannot be answered from the available tables. After two failures, the honest response is "I could not find a column for X — did you mean one of these?", which is more useful than a third guess.


The failure this does not catch

Everything above ensures the SQL is valid. None of it ensures the SQL is right.

Valid, executable, and wrong

The residual risk
Question'What was revenue last month?'
GeneratedSUM(gross_total) FROM ordersValid column, valid table, runs perfectly
The problemgross_total includes tax and shippingAnd no filter on financial_status, so cancelled orders are counted
ResultRevenue overstated ~24%No error at any layer. Every guardrail passed.
This is why the SQL has to be visible. Layers 1–4 guarantee the query is well-formed against your schema. Only a human — or a semantic layer that removed the choice — can confirm it answers the question that was asked.

Two mitigations, and they are the ones that matter most:

  1. Column descriptions that say which column not to use. gross_total described as "includes tax and shipping — use net_total for revenue reporting" moves the choice from a guess to a read.
  2. A semantic layer that removes the choice entirely, by exposing net_revenue and not exposing gross_total.

Frequently asked questions

Does a bigger model fix this?

It reduces the rate and does not change the shape. A larger model with no schema in context still guesses; a smaller model with the right schema, a dry run and a repair loop is more reliable than a larger one without them. The architecture matters more than the model here.

Should I fine-tune on my schema?

Almost never worth it. Schemas change and a fine-tune goes stale immediately, whereas retrieval is always current. Fine-tuning can help with house SQL style or dialect quirks; for schema knowledge, retrieval wins on both accuracy and maintenance.

How much schema is too much?

Watch two things: token cost per question, and whether the model starts picking deprecated or near-duplicate tables. The second symptom appears before the first becomes painful, and it is the one that produces wrong answers rather than expensive ones.

What if a dry run is not available?

Most engines offer something equivalent — EXPLAIN in Postgres, EXPLAIN or a LIMIT 0 execution elsewhere. If truly nothing is available, parse the generated SQL and check every referenced identifier against your cached schema before running. Less thorough, and far better than nothing.

Does this slow things down?

A dry run is sub-second and the repair loop only fires on failure. The added latency on a successful query is negligible, and on a failing one it converts an error the user would have seen into a corrected query they never knew about.


The summary

  • Hallucinated columns are a retrieval failure, not a reasoning failure. The model was asked to write SQL against a schema it could not see.
  • Retrieve real schema — names, types, modes, descriptions, partition columns — from the warehouse.
  • Constrain it. Too much schema causes wrong-table selection, which is subtler and worse than an invalid column.
  • Validate with a dry run before executing. Free, sub-second, catches every invalid identifier, and returns the byte estimate so you can cap cost before you pay it.
  • Repair with the literal error text, capped at two attempts, then ask the human.
  • None of this catches a valid but wrong query. Column descriptions and a semantic layer address that; showing the SQL is what makes it catchable at all.
Free tool

BigQuery Cost Estimator

Estimate what a query will cost before you run it — from validator bytes, with a table-scan simulator and a paste-your-query cost audit. On-demand BigQuery pricing, made concrete.

CR

Chinmay Raibagkar

About author →

Founder of DataLens AI. He helps non-technical teams read their ad and database numbers with confidence — which number to trust, what to do next, and what to ignore.