fix(errors): say which failure a qualified column reference hit (P40 … - #69
Merged
Merged
Conversation
…piece 1)
"Column 'a.path' not found. Table 'a' may not support qualified column
names" was the fallback for every unresolvable qualified reference, written
out at three call sites. Its central claim is essentially never true —
qualified names work — so it sends the reader after a feature limitation
instead of at their query.
It has now misdirected two separate investigations. It opened P40 ("maybe
table doesn't support qualified columns"), and on 2026-09-06 it cost a
second afternoon on a query with no generator in it at all:
WITH a AS (SELECT 'hello_world' AS path)
SELECT SPLIT_PART(a.path, '_', 1) -- no FROM a
That is an out-of-scope reference and nothing more; DuckDB rejects it with
"Referenced table \"a\" not found!". Adding FROM a returns 'hello'.
Two genuinely different failures were sharing one message, so split them:
prefix not in scope -> Unknown table or alias 'a' in 'a.path'. The query
selects from 'DUAL'. A CTE has to be named in a
FROM clause before its columns can be referenced.
column missing -> Column 'nope' not found in 'a'.
Available columns: path, id
The worst of the three sites was the SELECT-list one, which branched on
whether any column carried a qualified_name and, if none did, blamed
qualification. For a single table or a CTE no column is qualified, so the
heuristic fired on the common case and was wrong every time.
The in-scope test is deliberately generous — table name, resolved alias, or
any column's qualified-name prefix. A false "in scope" costs only a less
pointed message; a false "unknown table" would reintroduce exactly the
confident wrong explanation this removes.
Message logic now lives in one module rather than three copies, the R9/R11
lesson applied before it becomes a finding. Five unit tests, one asserting
the old wording cannot come back. Parity contract holds at 156 AGREE / 181
cases; full suite green.
Pieces 2 (resolve generator args against the real source table) and 3
(row-wise explode) of P40 are untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JBEUeckCwmWXoWTpQUTDqP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…piece 1)
"Column 'a.path' not found. Table 'a' may not support qualified column names" was the fallback for every unresolvable qualified reference, written out at three call sites. Its central claim is essentially never true — qualified names work — so it sends the reader after a feature limitation instead of at their query.
It has now misdirected two separate investigations. It opened P40 ("maybe table doesn't support qualified columns"), and on 2026-09-06 it cost a second afternoon on a query with no generator in it at all:
That is an out-of-scope reference and nothing more; DuckDB rejects it with "Referenced table "a" not found!". Adding FROM a returns 'hello'.
Two genuinely different failures were sharing one message, so split them:
prefix not in scope -> Unknown table or alias 'a' in 'a.path'. The query
selects from 'DUAL'. A CTE has to be named in a
FROM clause before its columns can be referenced.
column missing -> Column 'nope' not found in 'a'.
Available columns: path, id
The worst of the three sites was the SELECT-list one, which branched on whether any column carried a qualified_name and, if none did, blamed qualification. For a single table or a CTE no column is qualified, so the heuristic fired on the common case and was wrong every time.
The in-scope test is deliberately generous — table name, resolved alias, or any column's qualified-name prefix. A false "in scope" costs only a less pointed message; a false "unknown table" would reintroduce exactly the confident wrong explanation this removes.
Message logic now lives in one module rather than three copies, the R9/R11 lesson applied before it becomes a finding. Five unit tests, one asserting the old wording cannot come back. Parity contract holds at 156 AGREE / 181 cases; full suite green.
Pieces 2 (resolve generator args against the real source table) and 3 (row-wise explode) of P40 are untouched.
Claude-Session: https://claude.ai/code/session_01JBEUeckCwmWXoWTpQUTDqP