dbt-labs/dbt-core · error · IndexError
neither '{left}' nor '{right}' has a column '{src}'
Error message
neither '{left}' nor '{right}' has a column '{src}' What it means
During view SQL generation, qualify() resolves a source column name to the alias of the underlying table that provides it. For a join source it checks the left table first, then the right (left wins, matching the information schema's own projection). If the requested column exists in neither joined index table, view construction fails with this error. Like the other parse-safe errors, it reflects a mistake in the static VIEWS declaration, not user data.
Source
Thrown at crates/dbt-index-core/src/info_schema/parse_safe.rs:754
for (table, resource_type) in DAG_SIDE_TABLES {
arms.push(select(table, Some(resource_type))?);
}
Ok(format!(
"CREATE OR REPLACE VIEW {VIEW_SCHEMA}.{} AS {}",
quote(self.name),
arms.join(" UNION ALL "),
))
}
/// Qualify a source column with the alias of the table it comes from. For a join the
/// left table wins, as it does in the information schema's own projection.
fn qualify(&self, src: &str) -> Result<String, IndexError> {
match self.src {
Src::Table(_) => Ok(format!("{T}.{}", quote(src))),
Src::Join { left, .. } if has_column(left, src) => Ok(format!("{L}.{}", quote(src))),
Src::Join { right, .. } if has_column(right, src) => Ok(format!("{R}.{}", quote(src))),
Src::Join { left, right, .. } => Err(self.err(format!(
"neither '{left}' nor '{right}' has a column '{src}'"
))),
Src::Own => Err(self.err("must read an index table".to_string())),
}
}
fn err(&self, msg: String) -> IndexError {
IndexError::Other(format!("parse-safe view '{}': {msg}", self.name))
}
}
/// Every index table [`VIEWS`] reads, deduplicated.
pub fn base_tables() -> Vec<&'static str> {
VIEWS
.iter()
.flat_map(|v| v.base_tables())
.collect::<BTreeSet<_>>()
.into_iter()View on GitHub (pinned to 0267ce9170)
Solutions
- Correct the column's `src` name in the VIEWS entry to a column that exists in the left or right join table (verify with schema_for / has_column).
- If the column truly exists in neither table, drop it from the view's cols list or change the view's Src to include a table that has it.
- If a join-table column was renamed, update the information-schema spec (col.src) and any view entries referencing the old name together.
Example fix
// before (VIEWS entry referencing removed column)
cols: &["unique_id", "raw_code"], src: Src::Join { left: "nodes", right: "compiled", .. }
// after
cols: &["unique_id", "compiled_code"], src: Src::Join { left: "nodes", right: "compiled", .. } Defensive patterns
Strategy: validation
Validate before calling
// Verify every view column exists in one of the join tables before building SQL
fn join_cols_exist(src: &Src, cols: &[&str]) -> Vec<String> {
if let Src::Join { left, right, .. } = src {
cols.iter()
.filter(|c| !has_column(left, c) && !has_column(right, c))
.map(|c| format!("column '{c}' missing from both '{left}' and '{right}'"))
.collect()
} else {
vec![]
}
} Try / catch
match view.create_view_sql() {
Ok(sql) => execute(sql),
Err(IndexError::Other(msg)) if msg.contains("has a column") => {
eprintln!("view spec references unknown column (developer fix needed): {msg}");
}
Err(e) => return Err(e),
} Prevention
- When renaming/removing an index table column, grep VIEWS for the old `src` name in the same change.
- Add a test that validates every view entry's cols against its Src tables via has_column.
- Keep per-table schema definitions (schema_for) as the single source of truth for column names.
When it happens
Trigger: A VIEWS entry declares a column whose `src` name does not exist in either table of its Src::Join { left, right, .. } spec (checked via has_column against each table's schema), and create_view_sql() calls qualify() for it.
Common situations: Renaming or removing a column in one of the index tables (schema_for) without updating the view spec that joins that table and references the old column name; or copy-pasting a cols entry from a single-table view into a join view where the column only lives in a third table.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- must read an index table
- no expression for '{col}'
- inconsistent park_timeout state: {n}
- inconsistent state in unpark
- failed to generate unique thread ID: bitspace exhausted
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/ff33e0ff2fab4435.
Report an issue: GitHub.