dbt-labs/dbt-core · error · InvalidOperation
zip requires at least 1 argument
Error message
zip requires at least 1 argument
What it means
zip() combines two or more sequences element-wise (optionally with a fillvalue/default for uneven lengths, matching Python's itertools.zip_longest). It requires at least one positional argument; calling it with none throws this InvalidOperation error before any zipping happens.
Source
Thrown at crates/dbt-jinja-utils/src/functions/base.rs:838
/// Return an iterator of tuples where each tuple contains the i-th element from each of the input iterables.
/// dbt's zip also supports a custom kwarg `fillvalue` (default=None) to match the longest iterable.
///
/// Args:
/// *iterables: Two or more iterables
/// fillvalue: (optional) Value to fill in shorter iterables, default=None
///
/// Example:
/// ```jinja
/// {% set list1 = [1, 2] %}
/// {% set list2 = ['a', 'b', 'c'] %}
/// {% set pairs = zip(list1, list2, fillvalue='N/A') %}
/// -- Returns [(1, 'a'), (2, 'b'), ('N/A', 'c')]
/// ```
pub fn zip_fn() -> impl Fn(&[Value], Kwargs) -> Result<Value, Error> {
move |args: &[Value], kwargs: Kwargs| -> Result<Value, Error> {
if args.is_empty() {
return Err(Error::new(
ErrorKind::InvalidOperation,
"zip requires at least 1 argument",
));
}
let default = match (kwargs.get::<Value>("default"), args.get(1)) {
(Ok(value), _) => Some(value),
(_, Some(value)) => Some(value.clone()),
_ => None,
};
// Try to convert each argument to an internal Vec<Value>
let mut iterators: Vec<Vec<Value>> = Vec::new();
for arg in args {
match arg.try_iter() {
Ok(iter) => iterators.push(iter.collect()),
Err(_) => return Ok(default.unwrap_or_else(|| Value::from(()))),
}View on GitHub (pinned to 0267ce9170)
Solutions
- Pass at least two lists to zip: zip(list1, list2)
- If lists may be absent, guard: zip(list1, list2) only when both are defined and sequences
- Pass empty lists instead of omitting arguments: zip([], [])
Example fix
// before
{% set pairs = zip() %}
// after
{% set pairs = zip(list1 or [], list2 or []) %} Defensive patterns
Strategy: validation
Validate before calling
{% if list1 is not sequence or list2 is not sequence %}
{{ exceptions.raise_compiler_error('zip needs at least two lists in ' ~ this) }}
{% endif %}
{% set pairs = zip(list1, list2) %} Type guard
{% macro zip_safe(a, b) %}{{ return(zip(a if a is sequence else [], b if b is sequence else [])) }}{% endmacro %} Prevention
- Never call zip() with zero positional arguments; pass [] instead
- Coalesce undefined lists: list1 or []
- Verify dynamic argument lists actually contain arguments before calling
When it happens
Trigger: Calling zip() with zero positional arguments, e.g. a dynamically built argument list that ended up empty, or zip(default='N/A') with kwargs only.
Common situations: Lists built via template loops that turned out empty-of-arguments rather than being empty lists; refactors dropping the list arguments; confusion between the 'default' kwarg and positional fillvalue handling.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- diff_of_two_dicts requires exactly 2 arguments
- set() requires 1 argument
- render requires exactly one argument (the string to render)
- set_strict requires exactly 1 argument
- has_var requires 1 argument
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/5adf9d539141cdbf.
Report an issue: GitHub.