Skip to content

FSDP fails when composed with CPU parameter offloading

Sharding and CPU offloading both move parameters, and each assumes it is the component deciding where a parameter lives. Enabling them together produces a failure during setup or the first step, in a stack that works correctly with either one alone.

Quick answer

Two memory managers are claiming the same parameters. Test each alone to confirm, then recover the memory from the activation side or from wider sharding rather than from offloading.

Distributed Training#fsdp#cpu-offload#offloading#composition#megatron#memory-saving

What this failure is

A composition failure in which parameter sharding and CPU offloading each claim authority over where a parameter resides, producing a setup-time or first-step error in a configuration where either feature alone succeeds.

Why it happens (the mechanism)

Both features exist to reduce resident parameter memory and both work by controlling placement. Sharding splits a parameter and records where each piece lives; offloading moves it to host memory and records that instead. Neither is written to defer to the other, so the composition has no agreed owner for a tensor, and the first thing that resolves placement finds a contradiction.

What you'll observe

  • Both features are documented and each works by itself
  • The failure appears at setup or on the first step rather than under memory pressure
  • Offloading was enabled precisely because memory was already tight, so simply removing it is not free
  • The error rarely names offloading, so the interaction is not obvious from the message

Common symptoms and what they mean

SymptomWhy it happens
Setup or the first training step failing with both sharding and CPU offloading enabledSharding divides a parameter across ranks and keeps authoritative placement metadata for each piece. Offloading relocates parameters to host memory and restores them on demand, keeping its own view of where each one is. Both are correct in isolation and each expects to be the authority, so composing them leaves two components disagreeing about a single tensor.
A device or placement error naming a parameter that offloading has moved to host memoryThe disagreement shows up early because placement is resolved during setup and on the first use of a parameter, not when memory runs short. That is why the failure looks unrelated to the memory pressure that motivated enabling offloading.
The identical configuration succeeding with offloading disabledSupport for the combination is a property of a specific implementation and version rather than of the idea, so a stack that documents both features separately may not support them together, and a version that works is not evidence a neighbouring one does.
The identical configuration succeeding with sharding disabled and offloading keptSharding divides a parameter across ranks and keeps authoritative placement metadata for each piece. Offloading relocates parameters to host memory and restores them on demand, keeping its own view of where each one is. Both are correct in isolation and each expects to be the authority, so composing them leaves two components disagreeing about a single tensor.

Which systems are affected

  • Megatron-style FSDP implementations combined with CPU offloading
  • Stacks where offloading is configured by a launcher and sharding by the training framework, so neither knows about the other
  • Configurations carried over from a single-device memory-saving setup into a sharded one
  • Any setup where a parameter's owner is ambiguous between two memory managers

How to confirm this is the problem

Apply the following checklist to a small reproduction: each box below is a positive signal that you are looking at this exact failure rather than a sibling in the same taxonomy.

  • Disable CPU offloading and re-run with sharding unchanged. Success isolates the interaction rather than either feature.
  • Disable sharding and re-run with offloading unchanged. Success on both single-feature runs confirms the composition is the problem.
  • Check whether the failure occurs at setup or on the first step rather than under sustained memory pressure, which distinguishes a placement disagreement from genuine exhaustion.

Example training logs (fingerprint)

training.log (synthetic fingerprint)
Megatron FSDP does not work with CPU_OFFLOADING
RuntimeError raised during setup with both parameter sharding and CPU offloading enabled

Timestamps and exact values vary across runs, but the pattern. An info-level start, an early WARN, an ERROR carrying the symptom. Is the actual fingerprint you should alert on. The Denpex platform flags this combination automatically.

Root cause, fix & prevention, signed in

Sign up free to see why this failure really happens, the exact remediation steps, and the production-grade prevention pattern. You also get 3 free full diagnoses for your own training logs.

Sign up free. Unlock the full analysis

No credit card · 3 free diagnoses · Instant access

Why the recommended fix works

Removing one claimant leaves a single authority and the contradiction disappears. Recovering the memory from activations works because activation memory is managed by a different mechanism entirely, so it does not compete for ownership of parameters. Widening sharding reduces the same footprint offloading was targeting, without a second manager.

Code examples

typical reference pattern
// Typical pattern:
import torch.optim as optim
optimizer = optim.AdamW(model.parameters(), lr=3e-4)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_training_steps)
for step in range(num_training_steps):
    optimizer.zero_grad()
    loss = model(batch)
    loss.backward()
    optimizer.step()
    scheduler.step()

Adapt the snippet to your framework. The same pattern holds for PyTorch Lightning, Hugging Face Trainer, DeepSpeed, Megatron-LM, and vLLM training wrappers. Where the wrapper exposes a config flag (for examplelr_scheduler_type in Trainer), prefer the flag over the imperative API to keep the schedule declarative and reproducible.

Best practices by model family

Model / StackRecommendationNotes
Sharding must stayWiden sharding or shard optimizer state furtherReduces the same footprint without a second memory manager.
Memory pressure is from activationsActivation checkpointing or a smaller microbatchActivation memory does not compete for parameter ownership.
Offloading is essentialPin a version where the pair is supportedSupport is a property of the implementation and moves between releases.
DiagnosingTest each feature alone firstTwo successful single-feature runs prove it is the composition.

With the fix vs without the fix

DimensionWith the fixWithout the fix
What each feature controlsBoth control parameter placementAssumed to address different resources
When the failure appearsAt setup or the first stepExpected under sustained memory pressure
Whether documentation implies supportDocumented separately, not necessarily togetherRead as both being supported at once

Real engineering notes

The instinct on hitting this is to look for a memory bug, because offloading was enabled under memory pressure and the failure arrives soon after. The timing is the clue that it is not: a genuine exhaustion appears when the workload grows, while a placement disagreement appears at setup or on the very first step regardless of size. Note which, before spending time on allocator settings.

Visual fingerprint

Two managers, one parameter
  sharding    : parameter split across ranks, placement metadata per shard
  offloading  : parameter relocated to host memory, restored on demand

        both enabled ->  who owns the placement of this tensor?
                          |
                 resolved at setup / first use -> contradiction
Sharding and offloading each maintain their own record of where a parameter lives. With both enabled there is no agreed owner, and the contradiction surfaces the first time placement has to be resolved rather than when memory runs short.

Root cause, fix & prevention

Frequently asked questions

Twelve targeted questions that engineers and on-call staff most commonly ask about this failure.

Both features are documented. Why can I not use both?
They are documented separately. Both control where a parameter lives, and support for composing them is a property of a specific implementation and version.
Is this an out-of-memory problem?
Usually not. A placement disagreement appears at setup or on the first step regardless of workload size, while genuine exhaustion appears as the workload grows.
I enabled offloading because I was out of memory.
Then recover it elsewhere: widen sharding, shard optimizer state further, or reduce activation memory, none of which claims ownership of parameters.
How do I confirm it is the combination?
Run each feature alone. Two successful single-feature runs and a failing combined run is the proof.

Don't just read the fix, diagnose your run

The encyclopedia tells you what went wrong. Denpex tells you what went wrong in YOUR training run. With your logs, your config, and your stack.