Skip to content

fix(errors): say which failure a qualified column reference hit (P40 … - #69

Merged
TimelordUK merged 1 commit into
mainfrom
fix/p40-column-resolution-message
Sep 6, 2026
Merged

fix(errors): say which failure a qualified column reference hit (P40 …#69
TimelordUK merged 1 commit into
mainfrom
fix/p40-column-resolution-message

Conversation

@TimelordUK

Copy link
Copy Markdown
Owner

…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.

Claude-Session: https://claude.ai/code/session_01JBEUeckCwmWXoWTpQUTDqP

…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
@TimelordUK
TimelordUK merged commit e13b90f into main Sep 6, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant