dbt-labs/dbt-core · error
Schema not found for canonical FQN: {}
Error message
Schema not found for canonical FQN: {} What it means
DelayedTableProvider caches Arrow schemas keyed by canonical fully-qualified table name in a schema_store. When `schema()` is called, the entry for this table's canonical FQN must already have been populated by an earlier registration step; if it is absent, the code panics rather than returning a wrong or empty schema. This is an internal invariant: a schema should never be requested before it is registered.
Source
Thrown at crates/dbt-df-providers/src/delayed_table.rs:78
schema_store: schema_cache,
data_store,
data_provider: OnceLock::new(),
}
}
}
#[async_trait::async_trait]
impl TableProvider for DelayedDataTableProvider {
fn as_any(&self) -> &dyn Any {
self
}
fn schema(&self) -> Arc<arrow_schema::Schema> {
let schema_entry = self
.schema_store
.get_schema(&self.canonical_fqn)
.unwrap_or_else(|| {
panic!("Schema not found for canonical FQN: {}", self.canonical_fqn);
});
schema_entry.inner().clone()
}
/// Ensures the physical data provider exists before delegating to it.
async fn scan(
&self,
state: &dyn Session,
projection: Option<&Vec<usize>>,
filters: &[Expr],
limit: Option<usize>,
) -> Result<Arc<dyn datafusion::physical_plan::ExecutionPlan>, DataFusionError> {
// Set the data provider here...
let schema = self.schema();
let provider = if let Some(provider) = self.data_provider.get() {
provider.clone()
} else {
let provider = make_listing_table_provider(View on GitHub (pinned to 0267ce9170)
Solutions
- Ensure the pipeline registers the schema via schema_store.get/insert with the exact same canonical FQN before any schema()/scan() call.
- Log and compare the canonical_fqn used at registration time against the one used at lookup to find qualification mismatches.
- Verify the upstream model/table actually completed building before querying the delayed provider.
- Replace the panic with a fallible schema() returning Result so callers can surface 'schema not yet available' cleanly.
Defensive patterns
Strategy: validation
Validate before calling
// before requesting the schema, verify registration happened
if schema_store.get_schema(&canonical_fqn).is_none() {
return Err(anyhow!("schema for {} not yet registered", canonical_fqn));
} Try / catch
// use a fallible accessor instead of the panicking schema()
match provider.try_schema() {
Ok(schema) => schema,
Err(e) => bail!("delayed table {} has no registered schema: {}", fqn, e),
} Prevention
- Always register the schema in schema_store under the exact canonical FQN before planning/scan.
- Share one FQN-normalization helper so writer and reader keys cannot diverge.
- Await model completion before constructing providers for its relation.
- Prefer returning Result over panic in library code so missing schemas surface as user-facing errors.
When it happens
Trigger: Calling `schema()` (directly or via `scan()`) on a DelayedTableProvider whose canonical_fqn was never inserted into schema_store — e.g. the registration/planning step that populates the store was skipped, the FQN normalization differs between writer and reader, or a race dropped the entry before read.
Common situations: Querying a dbt model's table relation before the model finished building; a plan referencing a relation whose schema registration failed earlier in the pipeline; case- or catalog-qualification mismatches producing a canonical FQN that doesn't equal the key used at registration.
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
- `EnterGuard` values dropped out of order. Guards returned by
- {e} {:?}
- {e}
- inconsistent park state; actual = {actual}
- inconsistent park_timeout state; actual = {actual}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/4e18a5c3ff01ba0a.
Report an issue: GitHub.