Tensor on device meta is not on the expected device: a device mismatch from a parameter never materialised
A model built with automatic device placement runs until one submodule executes with a parameter still on the placeholder device. Meta tensors carry shape and dtype but no data, so the operation refuses rather than computing on nothing, and the error names a device that is not a device at all.
A parameter was never given real data. Meta tensors are shape-only placeholders, and one of them reached a live operation. Find the submodule in the traceback, check it against the placement map, and place it explicitly.
What this failure is
A forward-pass failure in which a parameter left on the meta placeholder device meets a real tensor in an operation, because automatic placement never attached a hook to materialise the submodule that owns it.
Why it happens (the mechanism)
Large-model loading deliberately separates structure from data so a model larger than one device can be described before it is populated. That separation is safe only while every parameter is subsequently materialised, and the mechanism responsible knows only about the modules it enumerated. Anything outside that enumeration keeps its placeholder, and a placeholder is indistinguishable from a real parameter until an operation needs its values.
What you'll observe
- Meta is not a real device, so the message reads as nonsense on first encounter
- Most of the model works, which points suspicion at the input rather than the weights
- The failing submodule is often a secondary encoder that placement treated differently from the main network
- The traceback ends in shape-inference internals, far from the placement decision that caused it
Common symptoms and what they mean
| Symptom | Why it happens |
|---|---|
| RuntimeError: Tensor on device meta is not on the expected device cuda:0 | Loading a large model starts by building it without data. Every parameter is a meta tensor: correct shape, correct dtype, no storage. Placement then decides where each submodule will live and hooks are attached to bring the real weights in at the right moment. A parameter that no hook covers stays a shape with nothing behind it. |
| The exception raised from elementwise shape-inference internals rather than from a kernel launch | The failure appears in shape inference rather than at a kernel because that layer runs first and it can see the contradiction immediately. One operand is on the accelerator, another exists nowhere, and there is no meaningful result to compute, so it raises instead of launching anything. |
| Forward passing through an offload hook wrapper immediately before the failing operation | The gap is usually structural rather than random. A submodule reached by a path placement did not walk, a component added to a pipeline after the map was built, or a parameter created during initialisation rather than loaded from the checkpoint will all be left behind by a mechanism that only knows about what it enumerated. |
| One submodule affected while the rest of the pipeline runs normally | Loading a large model starts by building it without data. Every parameter is a meta tensor: correct shape, correct dtype, no storage. Placement then decides where each submodule will live and hooks are attached to bring the real weights in at the right moment. A parameter that no hook covers stays a shape with nothing behind it. |
Which systems are affected
- Automatic device placement, which loads a skeleton on the placeholder device and fills it in per submodule
- Offload hooks that move weights onto the accelerator immediately before a submodule runs and off it afterwards
- Multi-component pipelines where a vision or text encoder is placed separately from the main network
- Modules constructed after placement was computed, which no hook was ever attached to
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.
- ✓Walk the model's parameters and buffers after loading and report any whose device is the placeholder. The list names exactly what was missed.
- ✓Compare the failing submodule's name against the placement map. A submodule with no entry was never scheduled to be materialised.
- ✓Load the same model onto a single device without automatic placement. Running correctly there confirms placement rather than the model or the input.
Example training logs (fingerprint)
RuntimeError: Tensor on device meta is not on the expected device cuda:0!
File ".../torch/_prims/__init__.py", in _prim_elementwise_meta
File ".../torch/_library/fake_impl.py", in meta_kernel
File ".../accelerate/hooks.py", in new_forwardTimestamps 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
Placing the component explicitly gives its parameters real storage on a real device, so the operation has values on both sides and proceeds. Materialising the whole model achieves the same by leaving no placeholders anywhere. Neither changes how the model computes; they change whether the numbers exist at the moment they are required.
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 |
|---|---|---|
| Single component missed | Place that component explicitly | Cleanest when the rest of the pipeline is correct. |
| Model fits on one device | Materialise fully at load | No placeholders survive, so none can be reached. |
| Sequential pipeline offload | Register every component | Later additions are frequently not registered. |
| Parameters made at init | Materialise them after construction | A checkpoint-derived map cannot see them. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| What meta means | Shape and dtype with no storage | Read as an unusual accelerator |
| Which operand is at fault | The weight, always | Suspected to be the input |
| When it is detectable | Immediately after load, by traversal | Only when the module runs |
Real engineering notes
“The instinct is to look at the inputs, because the error mentions a device and inputs are what usually arrive on the wrong one. It is worth resisting for one minute and reading which side of the operation is on meta: an input can be misplaced, but it is never on meta, because inputs are made of data. Meta on either operand means a weight, and a weight on meta means placement, every time.”
Visual fingerprint
build skeleton every parameter on meta (shape only)
|
v
compute placement map enumerates modules it can see
|
v
attach hooks -> materialise on use
|
+--> covered module : real weights ✓
+--> module not in map : still on meta ✗ -> RuntimeError on forwardRoot cause, fix & prevention
Frequently asked questions
Twelve targeted questions that engineers and on-call staff most commonly ask about this failure.
What is device meta?
Is my input on the wrong device?
Why does most of the model work?
How do I catch this earlier?
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.