astral-sh/ruff · error

bindings must not be empty

Error message

bindings must not be empty

What it means

Bindings::from_union merges the per-element bindings of a union of callables into one value, using the first element as the accumulator for the shared elements buffer. The expect fires when the iterator is empty: from_union requires at least one Bindings to merge.

Source

Thrown at crates/ty_python_semantic/src/types/call/bind.rs:749

        &mut self,
        db: &'db dyn Db,
        generic_context: GenericContext<'db>,
    ) {
        for element in &mut self.elements {
            for item in &mut element.items {
                match item {
                    CallableItem::Regular(binding) => {
                        for overload in &mut binding.overloads {
                            overload.signature.generic_context = GenericContext::merge_optional(
                                db,
                                overload.signature.generic_context,
                                Some(generic_context),
                            );
                        }
                    }
                    CallableItem::Constructor(binding) => {
                        for overload in &mut binding.entry.overloads {
                            overload.signature.generic_context = GenericContext::merge_optional(
                                db,
                                overload.signature.generic_context,
                                Some(generic_context),
                            );
                        }
                        if let Some(downstream) = binding.downstream_constructor_mut() {
                            downstream.apply_generic_context_in_place(db, generic_context);
                        }
                    }
                }
            }
        }
    }

    /// Creates a new `Bindings` from an iterator of [`Bindings`]s for a union type.
    /// Each input `Bindings` becomes a union element, preserving any intersection structure.
    /// Panics if the iterator is empty.
    pub(crate) fn from_union<I>(callable_type: Type<'db>, bindings_iter: I) -> Self

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Handle the empty case at the call site: return a not-callable/unbound binding instead of calling from_union with no elements
  2. File a ty issue with the call expression (Never-typed callables and empty unions are the usual triggers)
  3. As a contributor: encode the non-empty requirement in the signature (take head plus tail, or return Option) instead of unwrapping next()

Example fix

// before
let merged = Bindings::from_union(callable_type, bindings_iter);

// after
let mut bindings_iter = bindings_iter.into_iter();
let Some(first) = bindings_iter.next() else {
    return Bindings::empty(callable_type);
};
let merged = Bindings::from_union(callable_type, once(first).chain(bindings_iter));
Defensive patterns

Strategy: validation

Validate before calling

let mut iter = bindings_iter.into_iter();
if let Some(first) = iter.next() {
    Bindings::from_union(callable_type, std::iter::once(first).chain(iter));
} else {
    // no callable elements to merge: produce a not-callable result instead of merging

Prevention

When it happens

Trigger: Calling from_union with an empty iterator - e.g., invoking a value whose callable-union elements all got filtered out before binding, or an empty union (Never-adjacent) reaching the call path.

Common situations: Empty-union edge cases in call inference; refactors of union-call handling where filtering can now remove every branch before from_union runs.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20). Data as JSON: /api/errors/e05e7f3dcf77fda0. Report an issue: GitHub.