deepseek-ai/DeepSeek-V3 · error · AssertionError

Key ${key} not found in mapping

Error message

Key ${key} not found in mapping

What it means

Thrown in convert.py's main loop (inference/convert.py:63): after renaming HF-style parameter names (self_attn→attn, mlp→ffn, weight_scale_inv→scale, e_score_correction_bias→bias), it takes the second-to-last dot component (key = name.split('.')[-2]) and looks it up in the hardcoded `mapping` dict (embed_tokens, q_proj, kv_a_proj_with_mqa, gate, down_proj, ...). Any checkpoint whose module names differ from the expected HF DeepSeek-V3 layout fails here.

Source

Thrown at inference/convert.py:63

    """
    torch.set_num_threads(8)
    n_local_experts = n_experts // mp
    state_dicts = [{} for _ in range(mp)]

    for file_path in tqdm(glob(os.path.join(hf_ckpt_path, "*.safetensors"))):
        with safe_open(file_path, framework="pt", device="cpu") as f:
            for name in f.keys():
                if "model.layers.61" in name:
                    continue
                param: torch.Tensor = f.get_tensor(name)
                if name.startswith("model."):
                    name = name[len("model."):]
                name = name.replace("self_attn", "attn")
                name = name.replace("mlp", "ffn")
                name = name.replace("weight_scale_inv", "scale")
                name = name.replace("e_score_correction_bias", "bias")
                key = name.split(".")[-2]
                assert key in mapping, f"Key {key} not found in mapping"
                new_key, dim = mapping[key]
                name = name.replace(key, new_key)
                for i in range(mp):
                    new_param = param
                    if "experts" in name and "shared_experts" not in name:
                        idx = int(name.split(".")[-3])
                        if idx < i * n_local_experts or idx >= (i + 1) * n_local_experts:
                            continue
                    elif dim is not None:
                        assert param.size(dim) % mp == 0, f"Dimension {dim} must be divisible by {mp}"
                        shard_size = param.size(dim) // mp
                        new_param = param.narrow(dim, i * shard_size, shard_size).contiguous()
                    state_dicts[i][name] = new_param

    os.makedirs(save_path, exist_ok=True)

    for i in trange(mp):
        save_file(state_dicts[i], os.path.join(save_path, f"model{i}-mp{mp}.safetensors"))

View on GitHub (pinned to 9b4e9788e4)

Solutions

  1. Inspect the failing key: print the original tensor name that produced it (add logging before the assert) and compare with mapping's keys
  2. Extend the mapping dict in convert.py with the missing key: 'new_module_name': ('target_name', shard_dim_or_None)
  3. Verify you are converting a checkpoint with the exact naming this script targets (DeepSeek-V3 HF format); for other revisions use the upstream repo's matching convert script
  4. Check for rename collisions: name.replace('gate', ...) style substring bugs — prefer exact component replaces

Example fix

# before (convert.py)
mapping = {
    ...
    "gate": ("gate", None),
}
# AssertionError: Key xxx not found in mapping

# after — add the missing module key with its new name and shard dim
mapping = {
    ...
    "gate": ("gate", None),
    "xxx": ("yyy", 0),  # shard dim 0 for column-parallel, 1 for row-parallel, None for replicated
}
Defensive patterns

Strategy: validation

Validate before calling

from safetensors import safe_open
from convert import mapping

with safe_open("model-00001-of-000163.safetensors", framework="pt") as f:
    bad = set()
    for name in f.keys():
        n = name[len("model."):] if name.startswith("model.") else name
        n = n.replace("self_attn", "attn").replace("mlp", "ffn") \
             .replace("weight_scale_inv", "scale").replace("e_score_correction_bias", "bias")
        key = n.split(".")[-2]
        if key not in mapping:
            bad.add((name, key))
    assert not bad, f"unmapped keys: {sorted(bad)[:10]}"

Type guard

def key_is_mapped(name: str, mapping: dict) -> bool:
    key = name.split(".")[-2]
    return key in mapping

Try / catch

try:
    main(hf_ckpt_path, save_path, n_experts, mp)
except AssertionError as e:
    if "not found in mapping" in str(e):
        raise SystemExit(
            "Checkpoint naming differs from expected HF DeepSeek-V3 layout. "
            "Inspect the key in the message and extend `mapping` in convert.py."
        )
    raise

Prevention

When it happens

Trigger: Running convert.py --hf-ckpt-path with: a checkpoint from a different/newer HF model revision that renamed modules (e.g. new attention or quantization keys), a DeepSeek-R2/other-variant checkpoint with keys like xxx not in mapping, a plain (non-HF) safetensors file, or names where the replacement chain produces an unexpected second-to-last token (e.g. after 'mlp'→'ffn', 'gate_proj'→... the split lands on something unmapped like 'e_score_correction_bias' paths where key becomes 'bias' before mapping).

Common situations: Upgrading transformers/HF checkpoint revisions where naming changed; converting V2/V3.1/V3.2-Exp checkpoints whose router or expert-parallel keys differ; scale tensors named differently (weight_scale vs weight_scale_inv) so 'scale' key never appears or an unknown key appears.

Related errors


AI-assisted analysis of deepseek-ai/DeepSeek-V3@9b4e9788e4 (2026-08-14). Data as JSON: /api/errors/8703f7b4d1e39362. Report an issue: GitHub.