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.
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.
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
| Symptom | Why it happens |
|---|---|
| KeyError: 'lm_head.weight' raised while preparing the model | Weight 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 parameters | FSDP2 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 false | The 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 version | Weight 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)
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 configTimestamps 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 analysisNo 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 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 / Stack | Recommendation | Notes |
|---|---|---|
| Causal LM with tied embeddings | Set tie_word_embeddings to false before sharding | Gives the head its own tensor so the mapping has two entries. |
| Tying must be preserved | Untie, shard, then restore the relationship | The ambiguity only exists while the mapping is built. |
| Failure appears on save | Same fix; the optimizer path shares the mapping | The missing name breaks state handling identically. |
| Loading a state dict without the tied name | Load non-strictly and copy the embedding into the slot | The value is available under the other alias. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| What the KeyError means | A name that aliases an already-mapped tensor | Read as a parameter missing from the model |
| Why FSDP2 specifically | Each parameter becomes a DTensor with its own placement | Assumed to behave like the previous implementation |
| The warning above the traceback | Names the configuration change that fixes it | Skipped 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
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' -> KeyErrorRelated failures to investigate next
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 worked under the older FSDP.
Will untying change my model?
Mine fails on save, not on prepare.
References
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.