Skip to content

MLX’s “Received Parameters Not in Model” Error

9 min read · updated August 11, 2026

ValueError: Received parameters not in model: ... followed by a list of weight names. MLX is telling you that the checkpoint contains tensors the module tree it built has no home for — and the names it lists say which of three things happened.

Where the error comes from

MLX’s nn.Module.load_weights defaults to strict matching. It walks the module tree, collects the expected parameter paths, and compares them against the keys in the file. Anything in the file with no corresponding parameter is collected into an extras set, and the loader raises rather than ignoring it. The message is generated from that set, which is why it always ends with a list.

Strictness is deliberate. Silently dropping unmatched weights gives you a model that loads and produces subtly wrong output — a missing layer-norm scale or an unloaded projection is not visible until quality is bad in a way nobody can trace. Refusing to load is the safer failure, and this error is therefore working as designed even when it is inconvenient.

The mirror-image error exists too: parameters the model expects and the file does not have. If you see that instead, the checkpoint is incomplete or sharded and you have loaded only one shard.

The listed names are the diagnosis

Read the extras before doing anything. The names follow the module tree, so model.layers.0.self_attn.q_proj.lora_a tells you both what the tensor is and where it was supposed to live. Three patterns cover most reports:

  • Names containing lora_a, lora_b, lora_A, lora_B or adapter — adapter weights against a model built without adapters.
  • Names ending in .scales or .biases — quantisation metadata against a model built as unquantised.
  • Names that look structurally different — a different layer naming scheme, extra projections, vision-tower prefixes, or an expert dimension — meaning the checkpoint belongs to another architecture or another model class.

If you want the full comparison rather than the truncated list, print both sides:

import mlx.core as mx
from mlx.utils import tree_flatten

w = mx.load("weights.safetensors")            # or the .npz
file_keys = set(w.keys())
model_keys = {k for k, _ in tree_flatten(model.parameters())}

print("in file, not in model:", sorted(file_keys - model_keys)[:20])
print("in model, not in file:", sorted(model_keys - file_keys)[:20])

Both directions matter. Extras alone suggest a superset; extras plus missing suggests a rename, which points at an architecture or version mismatch rather than at leftovers.

Cause 1: adapter or fusion leftovers

After a LoRA fine-tune, the adapter file holds only the low-rank matrices. Loading that file into a base model fails because the base model has no lora_a parameters — the adapter has to be applied to a model that has been given adapter layers, or fused into the base weights first.

Fusion is the usual answer, and it is also a place this error appears in reverse. A fuse step that leaves adapter tensors in the output file produces a checkpoint that no plain model will accept: the fused weights are correct and the residual adapter keys are extras. If your fused model raises this and the extras are LoRA names, the fuse did not complete or the output directory mixes files from two runs.

The practical rules: never mix an adapter directory and a fused directory; regenerate the fused model rather than deleting keys by hand; and confirm that the config in the output directory describes the fused model, since MLX builds the module tree from that config and a stale config is what produces a tree that does not match its own weights. How LoRA weights relate to base weights explains why the two are separable in the first place.

Cause 2: quantisation the model was not told about

A quantised MLX model stores, for each quantised linear layer, the packed weights plus scales and biases. Those extra tensors only exist in the module tree if the model has been quantised before loading — MLX does that by reading a quantisation block from the config and converting the relevant modules first.

So this error with .scales in the extras means the config used to build the model did not describe the quantisation the weights have. Common ways to arrive there: downloading a 4-bit or 8-bit community conversion but pointing the loader at the original repository’s config; copying weights between directories without the config; converting with one MLX version and loading with another whose config key names differ.

The fix is to load the model and its config from the same directory, which is what the high-level loader does for you. If you are building the model by hand, quantise the module tree before load_weights, using the group size and bit width recorded in the config rather than defaults.

Cause 3: a checkpoint for a different architecture

The remaining case is the one the row is named for: the weights belong to a model whose structure differs from the one being instantiated. MLX-Examples issues report it for freshly converted architectures where the conversion script mapped names the model implementation did not expect, and for multimodal checkpoints loaded into a text-only class, where the vision tower’s parameters are all extras.

Three checks, in order:

  1. Read model_type in the checkpoint’s config.json and confirm the code path you are using implements that type. A type with no implementation often falls back to a generic Llama-shaped model, which is where wholesale name mismatches come from.
  2. Check whether the conversion is newer than your MLX version. Support for an architecture arrives in a release; a conversion published against a newer release can use names your installed version does not build. Upgrading the package is the fix, not editing the weights.
  3. Compare the extras against the model card’s parameter list. If the extras are an entire subsystem — a vision encoder, a set of expert layers, a draft head — you are loading a checkpoint into the wrong class and should use the loader intended for it.

One thing not to do: passing strict=False to make the error go away. It will load, and the parameters in the extras will simply not be there. For an adapter that is guaranteed wrong output; for a quantisation mismatch it is a model with uninitialised scales. The error is cheaper than the debugging session that non-strict loading buys you.