dbt-labs/dbt-core · error · minijinja::Error (InvalidOperation)
Failed to convert payload to string
Error message
Failed to convert payload to string
What it means
After checking arity, write() converts the first argument with as_str(); if the payload is not a string (e.g. a dict, list, or number value from Jinja), conversion fails and this error is raised instead of writing garbage to disk.
Source
Thrown at crates/dbt-jinja-utils/src/phases/run/run_node_context.rs:700
impl Object for WriteConfig {
fn call(
self: &Arc<Self>,
_state: &State<'_, '_>,
args: &[MinijinjaValue],
_listeners: &[Rc<dyn RenderingEventListener>],
) -> Result<MinijinjaValue, Error> {
if args.is_empty() {
return Err(Error::new(
ErrorKind::InvalidOperation,
"write function requires payload argument".to_string(),
));
}
// Extract payload from args
let payload = match args[0].as_str() {
Some(s) => s,
None => {
return Err(Error::new(
ErrorKind::InvalidOperation,
"Failed to convert payload to string".to_string(),
));
}
};
// Write the file
match write_file(&self.run_file_path, &self.resource_type, payload) {
Ok(_) => {}
Err(e) => {
return Err(Error::new(
ErrorKind::InvalidOperation,
format!("Failed to write file: {e}"),
));
}
}
// Return empty string on successView on GitHub (pinned to 0267ce9170)
Solutions
- Stringify the payload before calling: {{ write(payload | tojson) }} for structured data.
- Use {{ write(payload | string) }} for simple values.
- Inspect the payload type with |tojson or a type test to confirm what you are passing.
Example fix
-- before
{{ write({'status': 'ok'}) }}
-- after
{{ write({'status': 'ok'} | tojson) }} Defensive patterns
Strategy: type-guard
Validate before calling
-- Jinja
{% if payload is not string %}
{{ write(payload | tojson) }}
{% else %}
{{ write(payload) }}
{% endif %} Type guard
-- Jinja: only call write when payload is a string
{% if payload is string %}{{ write(payload) }}{% endif %} Try / catch
match args[0].as_str() {
Some(s) => write_file(&path, &rt, s)?,
None => Err(Error::new(ErrorKind::InvalidOperation, "payload must be a string; use |tojson or |string")),
} Prevention
- Apply |tojson to any dict/list payloads and |string to scalars before write().
- Never pass raw macro return objects to write().
- Add a Jinja test covering non-string payloads for write().
When it happens
Trigger: Calling write() with a non-string first argument, e.g. {{ write({'key': 'value'}) }} or {{ write(my_list) }}, or a numeric value without |string.
Common situations: Passing structured data (dicts/lists) straight to write instead of rendering it; forgetting the |tojson or |string filter; macro returning an object rather than text.
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 must be a string
- Column 'name' must be a string
- Column 'data_type' must be a string
- write function requires payload argument
- {type(df)} is not a supported type for dbt Python materializ
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/ba9c245e4d8ee06e.
Report an issue: GitHub.