dbt-labs/dbt-core · error
Error always present on ShouldBe::ButIsnt variant
Error message
Error always present on ShouldBe::ButIsnt variant
What it means
A panic from `.expect()` in `try_new` immediately after the message rewrite: the code takes ownership of the error (`take_err()`) stored on a `ShouldBe::ButIsnt` variant and asserts it is always present. This error is then converted into a richer `Invalid <type> definition` fs error. The panic signals the same ShouldBe invariant was broken at the error-value level.
Source
Thrown at crates/dbt-parser/src/dbt_project_config.rs:117
// An unknown key produces the error message `expected struct <SelfType>` due to
// the recursive type. Catch the error here to inject a more descriptive error.
let err_msg = variant
.as_err_msg()
.expect("Error message always present on ShouldBe::ButIsnt variant");
let self_type = std::any::type_name::<S>()
.rsplit("::")
.next()
.unwrap_or_default();
let detail = if err_msg.contains(&format!("expected struct {self_type}")) {
format!("Unrecognized key `{key_path}`. Custom keys must go under `+meta`.")
} else {
err_msg.to_string()
};
let err = variant
.take_err()
.expect("Error always present on ShouldBe::ButIsnt variant");
let fs_err = yaml_to_fs_error(err, filename).with_context(format!(
"Invalid {} definition `{}`: {}",
S::type_name(),
key_path,
detail
));
emit_strict_parse_error(fs_err, dependency_package_name);
}
}
};
if !disallow_plus_prefix {
warn_plus_prefixed_resource_paths::<S>("", configs, "", false);
}
Ok(recur_build_dbt_project_config(
dbt_config,
configs,
"",
&on_error,View on GitHub (pinned to 0267ce9170)
Solutions
- Fix the producer so ButIsnt always carries an Err value
- Reproduce with the offending YAML key to identify which deserializer drops the error
- Upgrade/pin dbt-jinja-utils to a fixed version
- Replace the expect with a graceful fallback error to keep config parsing failing with a report instead of panicking
Example fix
// before
let err = variant.take_err().expect("Error always present on ShouldBe::ButIsnt variant");
// after
let err = variant.take_err()
.unwrap_or_else(|| DbtError::new(ErrorCode::InvalidConfigError, "invalid value")); Defensive patterns
Strategy: fallback
Try / catch
let err = variant.take_err().unwrap_or_else(|| {
DbtError::new(ErrorCode::InvalidConfigError, "invalid value")
}); Prevention
- Ensure every ShouldBe::ButIsnt construction carries an error value
- Test config parsing with unknown keys to keep the error path exercised
- Pin crate versions together when upgrading
When it happens
Trigger: Same path as the sibling expect: YAML config key deserialization produces `ShouldBe::ButIsnt` whose `take_err()` returns None while building the 'Invalid <S::type_name> definition' error.
Common situations: Only observed when internal serde plumbing constructs ButIsnt without carrying an error; typically after refactors of dbt_jinja_utils::serde or custom deserializers feeding project config parsing.
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
- Error message always present on ShouldBe::ButIsnt variant
- Should be able to serialize job labels
- yaml deserializes into config type
- ModelPropertiesEntry guaranteed to exist for model
- Schema not found for canonical FQN: {}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/3210aec479d856af.
Report an issue: GitHub.