pandas-dev/pandas · error · NotImplementedError

Parallel apply is not supported when raw=False and engine='n

Error message

Parallel apply is not supported when raw=False and engine='numba'

What it means

Raised by apply_series_numba (apply.py:1307) when engine='numba' is used with raw=False and the user requested parallel=True via engine_kwargs. Parallel numba apply is only supported on the raw=True path (where each chunk is a numpy array); the Series-passing numba path cannot safely share work across threads, so pandas rejects the combination explicitly.

Source

Thrown at pandas/core/apply.py:1307

        assert callable(self.func)

        series_gen = self.series_generator
        res_index = self.result_index

        results = {}

        for i, v in enumerate(series_gen):
            results[i] = self.func(v, *self.args, **self.kwargs)
            if isinstance(results[i], ABCSeries):
                # If we have a view on v, we need to make a copy because
                #  series_generator will swap out the underlying data
                results[i] = results[i].copy(deep=False)

        return results, res_index

    def apply_series_numba(self):
        if self.engine_kwargs.get("parallel", False):
            raise NotImplementedError(
                "Parallel apply is not supported when raw=False and engine='numba'"
            )
        if not self.obj.index.is_unique or not self.columns.is_unique:
            raise NotImplementedError(
                "The index/columns must be unique when raw=False and engine='numba'"
            )
        self.validate_values_for_numba()
        results = self.apply_with_numba()
        return results, self.result_index

    def wrap_results(self, results: ResType, res_index: Index) -> DataFrame | Series:
        from pandas import Series

        # see if we can infer the results
        if len(results) > 0 and 0 in results and is_sequence(results[0]):
            return self.wrap_results_for_axis(results, res_index)

        # dict of scalars

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Drop parallel=True from engine_kwargs when using raw=False with engine='numba'.
  2. If you need parallel numba, add raw=True so each call receives an ndarray: df.apply(func, raw=True, engine='numba', engine_kwargs={'parallel': True}).
  3. Keep parallel=False (default) and rely on numba's single-threaded JIT, or parallelize at a higher level with multiprocessing/concurrent.futures.

Example fix

// before
df.apply(func, engine='numba', engine_kwargs={'parallel': True})
// after
df.apply(func, raw=True, engine='numba', engine_kwargs={'parallel': True})
Defensive patterns

Strategy: validation

Validate before calling

parallel = (engine_kwargs or {}).get('parallel', False)
if engine == 'numba' and parallel and not raw:
    raise ValueError("parallel=True with engine='numba' requires raw=True")

Type guard

def numba_parallel_ok(engine: str, raw: bool, engine_kwargs: dict) -> bool:
    return not (engine == 'numba' and (engine_kwargs or {}).get('parallel') and not raw)

Try / catch

try:
    df.apply(func, engine='numba', engine_kwargs=engine_kwargs, raw=raw)
except NotImplementedError as e:
    if 'Parallel apply' in str(e):
        df.apply(func, engine='numba', raw=True, engine_kwargs=engine_kwargs)
    else:
        raise

Prevention

When it happens

Trigger: df.apply(func, engine='numba', engine_kwargs={'parallel': True}) with the default raw=False. Hit at apply.py:1306-1309 in apply_series_numba when engine_kwargs.get('parallel', False) is truthy.

Common situations: Copying a parallel-numba example that was written for raw=True; passing engine_kwargs from a config without checking the raw mode; assuming parallel works regardless of whether Series or ndarray is passed.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/c29c30524a24fd60. Report an issue: GitHub.