pandas-dev/pandas · error · NotImplementedError

Cannot apply ufunc to mixed DataFrame and Series inputs.

Error message

Cannot apply ufunc {ufunc} to mixed DataFrame and Series inputs.

What it means

NotImplementedError raised in the arraylike ufunc dispatch when a numpy ufunc is called with mixed DataFrame and Series inputs. pandas would previously raise an internal ValueError during alignment; now it explicitly states the combination is unsupported pending a future implementation.

Solutions

  1. Convert the Series to a DataFrame matching the desired axis: np.add(df, s.to_frame()).
  2. Use pandas arithmetic operators which handle alignment: df + s (broadcasts across columns) or df.add(s, axis=...).
  3. Align manually: reindex the Series to the DataFrame index/columns and pass it as a 2-D object.

Example fix

# before
np.add(df, s)  # df is DataFrame, s is Series
# after
df + s  # pandas operator handles alignment
Defensive patterns

Strategy: fallback

Validate before calling

import numpy as np, pandas as pd
def safe_ufunc(ufunc, df, s):
    if isinstance(df, pd.DataFrame) and isinstance(s, pd.Series):
        return df + s.to_frame() if ufunc is np.add else ufunc(df, s.to_frame())
    return ufunc(df, s)

Type guard

def is_mixed_df_series(a, b) -> bool:
    import pandas as pd
    return {type(a), type(b)} == {pd.DataFrame, pd.Series}

Try / catch

try:
    np.add(df, s)
except NotImplementedError as e:
    if 'mixed DataFrame and Series' in str(e):
        df + s  # pandas operator handles alignment
    else:
        raise

Prevention

When it happens

Trigger: np.add(df, series); np.multiply(df, series); any np.<ufunc>(DataFrame, Series) call.

Common situations: Vectorising math with numpy ufuncs and passing a Series (e.g. a row of weights) alongside a DataFrame.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/e12c6ae25024981f. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arraylike.py:336

            return NotImplemented

    # align all the inputs.
    types = tuple(type(x) for x in inputs)
    alignable = [
        x for x, t in zip(inputs, types, strict=True) if issubclass(t, NDFrame)
    ]

    if len(alignable) > 1:
        # This triggers alignment.
        # At the moment, there aren't any ufuncs with more than two inputs
        # so this ends up just being x1.index | x2.index, but we write
        # it to handle *args.
        set_types = set(types)
        if len(set_types) > 1 and {DataFrame, Series}.issubset(set_types):
            # We currently don't handle ufunc(DataFrame, Series)
            # well. Previously this raised an internal ValueError. We might
            # support it someday, so raise a NotImplementedError.
            raise NotImplementedError(
                f"Cannot apply ufunc {ufunc} to mixed DataFrame and Series inputs."
            )
        axes = self.axes
        for obj in alignable[1:]:
            # this relies on the fact that we aren't handling mixed
            # series / frame ufuncs.
            for i, (ax1, ax2) in enumerate(zip(axes, obj.axes, strict=True)):
                axes[i] = ax1.union(ax2)

        reconstruct_axes = dict(zip(self._AXIS_ORDERS, axes, strict=True))
        inputs = tuple(
            x.reindex(**reconstruct_axes) if issubclass(t, NDFrame) else x
            for x, t in zip(inputs, types, strict=True)
        )
    else:
        reconstruct_axes = dict(zip(self._AXIS_ORDERS, self.axes, strict=True))

    if self.ndim == 1:

View on GitHub (pinned to 3b7651241d)