Lightning-AI/pytorch-lightning · error · TypeError

Blocking backward sync is only possible if the module passed

Error message

Blocking backward sync is only possible if the module passed to `{self.__class__.__name__}.no_backward_sync` is wrapped in `DistributedDataParallel`. Got: {module.__class__.__name__}.

What it means

DDPStrategy.no_backward_sync(enabled=True) returns module.no_sync(), which only exists on torch's DistributedDataParallel wrapper. If the module you pass is a plain nn.Module (or the strategy hasn't wrapped it yet / you unwrapped it), a TypeError is raised telling you to pass the DDP-wrapped module.

Source

Thrown at src/lightning/fabric/strategies/ddp.py:268

            self.cluster_environment.set_world_size(self.num_nodes * self.num_processes)
        # `LightningEnvironment.set_global_rank` will do this too, but we cannot rely on that implementation detail
        # additionally, for some implementations, the setter is a no-op, so it's safer to access the getter
        rank_zero_only.rank = utils_rank_zero_only.rank = self.global_rank

    def _determine_ddp_device_ids(self) -> Optional[list[int]]:
        return None if self.root_device.type == "cpu" else [self.root_device.index]


class _DDPBackwardSyncControl(_BackwardSyncControl):
    @override
    def no_backward_sync(self, module: Module, enabled: bool) -> AbstractContextManager:
        """Blocks gradient synchronization inside the :class:`~torch.nn.parallel.distributed.DistributedDataParallel`
        wrapper."""
        if not enabled:
            return nullcontext()

        if not isinstance(module, DistributedDataParallel):
            raise TypeError(
                "Blocking backward sync is only possible if the module passed to"
                f" `{self.__class__.__name__}.no_backward_sync` is wrapped in `DistributedDataParallel`."
                f" Got: {module.__class__.__name__}."
            )
        return module.no_sync()

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Pass the wrapped module — use fabric.no_backward_sync(...) as a context manager which uses the strategy's wrapped model, or ensure strategy.setup(module) ran first
  2. Only call no_backward_sync when enabled=True is needed on accumulation steps; the method returns nullcontext() when enabled=False, so gating it avoids the check entirely
  3. Ensure the strategy actually is DDPStrategy (single-device or deepspeed strategies don't produce a DDP wrapper)

Example fix

# before
with fabric.strategy.no_backward_sync(raw_module):  # raw nn.Module
    ...
# after
with fabric.no_backward_sync(is_first_batch):  # uses wrapped fabric.model
    ...
Defensive patterns

Strategy: type-guard

Validate before calling

from torch.nn.parallel import DistributedDataParallel as DDP
if enabled and not isinstance(module, DDP):
    module = fabric.strategy.model if isinstance(fabric.strategy.model, DDP) else module
    # or skip no-sync on this step

Type guard

from torch.nn.parallel import DistributedDataParallel as DDP
from contextlib import nullcontext

def safe_no_backward_sync(strategy, module, enabled: bool):
    if not enabled or not isinstance(module, DDP):
        return nullcontext()
    return module.no_sync()

Prevention

When it happens

Trigger: Calling fabric.strategy.no_backward_sync(module) or using the fabric.no_backward_sync context with gradient accumulation while the model is a raw nn.Module — e.g. before strategy.setup(module), after strategy.unwrap_module(model), or with a non-DDP strategy fallback.

Common situations: Gradient-accumulation loops that skip the no-sync context on the last batch; passing fabric.model after it was unwrapped for logging; calling no_backward_sync before setup wrapped the module in DistributedDataParallel.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/75efde825de8eed0. Report an issue: GitHub.