Skip to content

FSDP2 raises a KeyError on a tied weight while sharding the model

A language model whose output projection shares its tensor with the input embedding fails to shard. When fully_shard rebuilds parameters as DTensors, the shared tensor appears once rather than twice, the mapping from old parameters to new ones loses the tied name, and preparation dies on a KeyError naming a weight that plainly exists in the model.

Quick answer

The weight is not missing, it is an alias. The output projection shares its tensor with the embedding, so the shard mapping records it once. Disable weight tying in the config, or untie before sharding and re-tie after.

Distributed Training#fsdp#fsdp2#fully_shard#tied-weights#lm_head#keyerror

What this failure is

A preparation-time failure in FSDP2 where two parameter names alias one tied tensor, so the mapping rebuilt during sharding records the tensor once and a lookup by the second name raises a KeyError.

Why it happens (the mechanism)

Sharding replaces every parameter with a new object and needs to know which new object corresponds to which old one. That correspondence is built from tensor identity, and identity is precisely what tying collapses. Two names go in, one entry comes out, and the name that lost the race is the one the error reports.

What you'll observe

  • The named weight is visibly present in the model, so the error reads as impossible
  • The failure happens during preparation, before any training step
  • The same model trains without complaint under the previous FSDP implementation
  • A warning about weight tying appears above the traceback and is easy to read past

Common symptoms and what they mean

SymptomWhy it happens
KeyError: 'lm_head.weight' raised while preparing the modelWeight tying means two parameter names refer to one tensor object. Code that walks named parameters therefore sees the tensor twice under two names, while code that builds a set or a dict keyed by the tensor sees it once. The mapping from pre-shard to post-shard parameters is built exactly that way, so the second name has no entry and the lookup raises.
Traceback through accelerator.prepare into _prepare_fsdp2, at a mapping built from old and new named parametersFSDP2 is more exposed to this than its predecessor because it replaces each parameter with a DTensor carrying its own placement. A tensor shared across two shard groups has no single well-defined placement, so tying is not a cosmetic detail the sharding layer can ignore.
A preceding warning suggesting the config be updated with tie_word_embeddings set to falseThe error names the weight rather than the tying, which sends people to look for a missing parameter. Nothing is missing: the name is a second alias for a tensor the mapping already consumed under its first alias.
KeyError reporting that a parameter in the optimizer could not be switched to its sharded versionWeight tying means two parameter names refer to one tensor object. Code that walks named parameters therefore sees the tensor twice under two names, while code that builds a set or a dict keyed by the tensor sees it once. The mapping from pre-shard to post-shard parameters is built exactly that way, so the second name has no entry and the lookup raises.

Which systems are affected

  • FSDP2 and fully_shard, which represent sharded parameters as DTensors
  • Causal language models that tie the output projection to the input embedding, which is most of them
  • Setups where the tied tensors would land in different shard groups, such as the embedding at the root and the head below it
  • Optimizer state handling, where the same missing key surfaces on save rather than on prepare

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.

  • Compare the identity of the output projection tensor with the input embedding tensor. If they are the same object, tying is in play and explains the missing name.
  • Read the lines immediately above the traceback for a warning about tied weights; it names the configuration change that resolves it.
  • Re-run with tying disabled in the configuration. Success confirms the alias rather than a genuinely absent parameter.

Example training logs (fingerprint)

training.log (synthetic fingerprint)
KeyError: 'lm_head.weight'
  File ".../accelerate/accelerator.py", in _prepare_fsdp2
    mapping = {p: new_named_params[n] for n, p in old_named_params.items()}
WARNING: model has tied weights; consider setting tie_word_embeddings=False in the config

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

Giving the output projection its own tensor makes the two names refer to two objects, so the mapping has an entry for each and the lookup succeeds. Untie-shard-retie achieves the same thing for a window long enough to build the mapping. Neither changes the mathematics of the model; they change whether the sharding layer can express it.

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
Causal LM with tied embeddingsSet tie_word_embeddings to false before shardingGives the head its own tensor so the mapping has two entries.
Tying must be preservedUntie, shard, then restore the relationshipThe ambiguity only exists while the mapping is built.
Failure appears on saveSame fix; the optimizer path shares the mappingThe missing name breaks state handling identically.
Loading a state dict without the tied nameLoad non-strictly and copy the embedding into the slotThe value is available under the other alias.

With the fix vs without the fix

DimensionWith the fixWithout the fix
What the KeyError meansA name that aliases an already-mapped tensorRead as a parameter missing from the model
Why FSDP2 specificallyEach parameter becomes a DTensor with its own placementAssumed to behave like the previous implementation
The warning above the tracebackNames the configuration change that fixes itSkipped as routine noise

Real engineering notes

The reflex on seeing a KeyError for a weight is to check whether the checkpoint is missing it, and that is always a dead end here. The tell is that the name in the error is the output projection specifically, which is the tied one in almost every causal language model. If you see any tied-weight name in a sharding traceback, go straight to the tying configuration rather than to the checkpoint.

Visual fingerprint

Two names, one tensor, one mapping entry
  before sharding
    model.embed_tokens.weight  ->  tensor A
    lm_head.weight             ->  tensor A     (same object)

  mapping keyed by tensor identity
    tensor A -> new DTensor        (one entry, not two)

  lookup by name 'lm_head.weight' -> KeyError
Both names point at one tensor, so a mapping keyed by tensor identity records a single entry. Looking that mapping up by the second name finds nothing, which is the KeyError, even though the parameter is present in the model.

Root cause, fix & prevention

Frequently asked questions

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

The parameter is clearly in my model. Why a KeyError?
It is present under two names that share one tensor. The shard mapping is keyed by tensor identity, so it holds one entry and the second name finds nothing.
It worked under the older FSDP.
FSDP2 gives each parameter its own DTensor placement, so a tensor shared across shard groups has no single valid placement. The older implementation did not need to resolve that.
Will untying change my model?
It stops the two tensors being one object. If you need the weights to stay equal, untie only around sharding and restore the relationship afterwards.
Mine fails on save, not on prepare.
Same cause. The optimizer state path uses the same mapping, and the missing alias breaks it there too.

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.