dbt-labs/dbt-core · error · InvalidOperation
local_md5's argument must be a string
Error message
local_md5's argument must be a string
What it means
`local_md5` hashes strings only; when its single argument is not a string (e.g. a number, boolean, list, or undefined value) the `as_str()` conversion fails and this error is raised. It exists to fail fast rather than hashing a Debug representation that would differ from dbt's expected output.
Solutions
- Convert to string before hashing: `local_md5(value | string)`
- Guard undefined variables with a default: `local_md5(var | default(""))`
- Ensure the source column/variable is a string type upstream
Example fix
// before
{% set h = local_md5(user_id) %}
// after
{% set h = local_md5(user_id | string) %} Defensive patterns
Strategy: type-guard
Validate before calling
{% if value is not string %}{% set value = value | string %}{% endif %} Type guard
{% macro as_str(v) %}{% if v is string %}{{ v }}{% else %}{{ v | string }}{% endif %}{% endmacro %} Prevention
- Apply the `| string` filter before hashing non-string values
- Default undefined vars: var('x', '') | string
- Confirm source columns are typed as strings
When it happens
Trigger: Calling `{{ local_md5(123) }}`, `{{ local_md5(my_list) }}`, or `{{ local_md5(undefined_var) }}` — any non-string value, including values rendered from YAML that arrive as ints/bools.
Common situations: Hashing a numeric ID directly from the warehouse, an undefined variable due to a missing config key, or a column value that dbt typed as a number.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- argument 'name' to has_var() has incompatible type; value…
- argument 'name' to var() has incompatible type; value is…
- local_md5 requires exactly 1 argument
- zip_strict requires all arguments to be iterable
- adapter not found in context
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/8e5ceb6443d224cc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-jinja-utils/src/functions/base.rs:1042
/// Args:
/// value: String to hash
///
/// Example:
/// ```jinja
/// {% set hash = local_md5("hello") %}
/// -- Returns "5d41402abc4b2a76b9719d911017c592"
/// ```
pub fn local_md5_fn() -> impl Fn(&[Value], Kwargs) -> Result<Value, Error> {
move |args: &[Value], _kwargs: Kwargs| -> Result<Value, Error> {
if args.len() != 1 {
return Err(Error::new(
ErrorKind::InvalidOperation,
"local_md5 requires exactly 1 argument",
));
}
let value = args[0].as_str().ok_or_else(|| {
Error::new(
ErrorKind::InvalidOperation,
"local_md5's argument must be a string",
)
})?;
// Create MD5 hasher
let result = format!("{:x}", md5::compute(value.as_bytes()));
Ok(Value::from(result))
}
}
/// Parse a dictionary of lists into a BTreeMap<String, Vec<String>>
fn parse_dict_of_lists(dict: &Value) -> Result<IndexMap<String, Vec<String>>, Error> {
let mut result = IndexMap::new();
// Iterate over the keys in the dictionary
for key in dict.try_iter()? {
// Get the value associated with the key
let value = dict.get_item(&key)?;View on GitHub (pinned to 0267ce9170)