Typeless binder: chained binary operators (`a || b || c`) break lineage with spurious schema error
- Dominant language
- Rust
- Stars
- 13.8k
- Forks
- 2.6k
- Avg merge
- 21h 31m
- Merged PRs (30d)
- 56
Description
### Summary
In the typeless binder (the inference path used when `--static-analysis` is not `strict`), a **chained binary operator** in the SELECT list — `a || b || c` — causes column-level lineage computation to fail with a spurious "no such field" schema error. A single binary operator (`a || b`) is fine, and function calls are fine at any nesting.
### Repro
Project: https://github.com/dbt-labs/scratch/tree/main/repros/typeless_binder_diagnostics
(pending merge of dbt-labs/scratch#277)
```bash
dbt deps && dbt seed
dbt clean
dbt compile --write-index --write-lineage
```
```
[warning] [LogicalPlanError (dbt1019)]: Failed to compute lineage for model.moms_flower_shop.stg_customers:
Schema error: No field named "ANALYTICS_DEV"."RAW"."RAW_CUSTOMERS"."FIRST_NAME". Did you mean 'A.STREET_NAME'?.
```
The offending line in `models/staging/stg_customers.sql` is:
```sql
c.first_name || ' ' || c.last_name as full_name,
```
### What's actually happening
Selecting the single model exposes the mechanism:
```bash
dbt compile --write-index --write-lineage -s stg_customers
```
```
[warning] [LogicalPlanError (dbt1019)]: Failed to compute lineage for model.moms_flower_shop.stg_customers:
Schema error: No field named "ANALYTICS_DEV"."RAW"."RAW_CUSTOMERS"."FIRST_NAME".
Valid fields are "C".__sdf_inference_column_target, "I".__sdf_inference_column_target, "A".__sdf_inference_column_target.
```
Every relation in scope is represented by a single placeholder column, `__sdf_inference_column_target`. Lineage computation then performs a **fully-qualified by-name lookup** (`"DB"."SCHEMA"."TABLE"."COLUMN"`) against that placeholder-only schema, which can never match.
### Minimal trigger
Each expression below was substituted as one extra SELECT item on `stg_customers`, with the original `full_name` concat removed:
| Expression | `dbt1019`? |
|---|---|
| `c.first_name` (bare ref) | no |
| `upper(c.first_name)` | no |
| `concat(c.first_name, c.last_name)` | no |
| `c.first_name \|\| c.last_name` (single binop) | no |
| `c.first_name \|\| ' '` (single binop) | no |
| `upper(c.first_name) \|\| ' '` | no |
| **`c.first_name \|\| ' ' \|\| c.last_name`** (chained) | **YES** |
| **`c.first_name \|\| c.last_name \|\| c.email`** (chained) | **YES** |
| **`a.city \|\| ' ' \|\| a.state`** (chained) | **YES** |
Two things worth calling out:
1. **Chaining is the trigger.** One binary operator binds fine; two or more nested ones fail. Function calls (`upper`, `concat`) are fine regardless of nesting.
2. **This is not source-specific, and not about a missing schema.** The last row uses alias `a` = `ref('raw_addresses')` — a **seed with a real, downloaded schema** — and fails identically:
```
Schema error: No field named "ANALYTICS_DEV"."DBT_EDEFARIA_RAW"."RAW_ADDRESSES"."CITY".
Valid fields are "C".__sdf_inference_column_target, "I".__sdf_inference_column_target, "A".__sdf_inference_column_target.
```
So this is a general defect in how chained binary expressions are resolved during lineage computation on the typeless path, not something about sources or inferred schemas specifically.
### Secondary problem: misleading "Did you mean"
In the full-project run the suggestion for `FIRST_NAME` is `'A.STREET_NAME'` — a column on an unrelated relation. The candidate set for the suggestion is evidently built from a different scope than the failed lookup, so the hint points the user at the wrong table.
### Expected
`c.first_name || ' ' || c.last_name as full_name` is ordinary, valid SQL that compiles and runs. It should not produce a schema error, and lineage for the model should be computed (or degrade silently) rather than failing.
### Version
```
dbt-fusion 2.0.0-preview.210 (vsce-v0.99.2-69-g753e9dd046 2026-08-20 16:13:10)
```
Adapter: Snowflake.
Contributor guide
Assessment
This issue has not been assessed yet.