Skip to content

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.

Quick answer

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.

Memory Management#meta-device#cpu-offload#device-map#accelerate-hooks#big-model-inference#wrong-device

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

SymptomWhy it happens
RuntimeError: Tensor on device meta is not on the expected device cuda:0Loading 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 launchThe 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 operationThe 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 normallyLoading 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)

training.log (synthetic 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_forward

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

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 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
Single component missedPlace that component explicitlyCleanest when the rest of the pipeline is correct.
Model fits on one deviceMaterialise fully at loadNo placeholders survive, so none can be reached.
Sequential pipeline offloadRegister every componentLater additions are frequently not registered.
Parameters made at initMaterialise them after constructionA checkpoint-derived map cannot see them.

With the fix vs without the fix

DimensionWith the fixWithout the fix
What meta meansShape and dtype with no storageRead as an unusual accelerator
Which operand is at faultThe weight, alwaysSuspected to be the input
When it is detectableImmediately after load, by traversalOnly 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

Where a parameter gets left behind
  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 forward
Materialisation is driven by the placement map. A module the map never enumerated keeps its placeholder parameters, and nothing detects that until the module is executed and an operation needs actual values.

Root 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?
A placeholder. A meta tensor has a shape and a dtype and no storage at all, which is how a model can be described before it is populated.
Is my input on the wrong device?
Almost certainly not. Inputs are made of data and are never on meta. A meta operand is a weight, and that means placement.
Why does most of the model work?
Because most of it was materialised. Only the submodule the placement map missed still holds placeholders, and it fails the first time it runs.
How do I catch this earlier?
Traverse the parameters after loading and assert none are on the placeholder device. It turns a mid-forward failure into an immediate one.

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.