Qwen3.8 (Qwen/Qwen3.8-2.4T-A95B, 2.4T total / A95B active) is not a new architecture. Its config declares Qwen3_5MoeForCausalLM / model_type: qwen3_5_moe_text — the same GDN-hybrid MoE backbone we already run token-exact (315/315 on Qwen3.6-35B-A3B). Every structural knob matches: head_dim 256, linear_key/value_head_dim 128, linear_num_key_heads 16, full_attention_interval 4, attn_output_gate true, partial_rotary_factor 0.25, rope_theta 1e7, mtp_num_hidden_layers 1, and the same tokenizer (vocab_size 248320). The deltas are pure scale (hidden 2048->8192, layers 40->92, experts 256->512, top-k 8->10, moe/shared intermediate 512->2048, linear V-heads 32->128), all config-driven.
Two things block loading it:
1. The architecture string is unregistered. ModelRegistry::Resolve is an exact string match with no aliasing (src/vllm/model_executor/models/model_registry.cpp:217-231); we register only Qwen3_5MoeForConditionalGeneration (qwen3_5_moe.cpp:215) and Qwen3_5ForConditionalGeneration (qwen3_5_dense.cpp:243). A text-only config falls through to RaiseForUnsupported.
2. The loader hardcodes the VL weight prefix. qwen3_5_weights.cpp:560,632,633,659 (and qwen3_5_dense_weights.cpp, 3 sites) look up model.language_model.*. Verified against the real checkpoints:
|
Qwen3.6-35B-A3B |
Qwen3.8-2.4T-A95B |
| embed |
model.language_model.embed_tokens.weight |
model.embed_tokens.weight |
| layer |
model.language_model.layers.0.linear_attn.* |
model.layers.0.linear_attn.* |
| experts |
...mlp.experts.gate_up_proj (3D stacked) |
...mlp.experts.gate_up_proj (3D stacked) |
| head |
lm_head.weight |
lm_head.weight |
The tensor names are identical modulo the prefix — same 3D-stacked experts, same shared_expert_gate, same top-level lm_head. So the existing loader is correct once the prefix is tolerant.
Upstream solves exactly this with a mapper on the text-only base class:
# vllm/model_executor/models/qwen3_5.py:296-300 @ origin/main
# Some community text-only checkpoints keep the extraneous
# `model.language_model.` prefix inherited from the VL training stack.
hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"model.language_model.": "model."})
Qwen3_5MoeForCausalLM is a thin text-only class over the same backbone (qwen3_5.py:443-449), and Qwen3_5ForCausalLM is pass over the shared base (:439).
Ahead-of-pin, and stated as such. Our parity pin is 555967922, whose registry has only the ForConditionalGeneration entries. The text-only arms were added upstream by PR #50210 / ad5d29db7 ("[Model] Support Qwen3.5 text-only dense and MoE models"), which is post-pin. This is therefore a deliberate forward port, not a mirror of the pin.
We cannot gate it on our hardware, and that is not hidden. 2.4T bf16 is ~4.8 TB; the only other released variant is Qwen/Qwen3.8-2.4T-A95B-FP8 at ~2.4 TB. GB10 has 128 GB unified, and no smaller Qwen3.8 sibling exists. So there is no token-exact oracle run for the 2.4T checkpoint. What IS gateable: config resolution, architecture dispatch, weight-name mapping, and byte-identical inertness of the existing 27B/35B/Coder gates. The run gate stays explicitly OWED and the row must not claim DONE on the 3.8 checkpoint.
Qwen3.8 (Qwen/Qwen3.8-2.4T-A95B, 2.4T total / A95B active) is not a new architecture. Its config declares
Qwen3_5MoeForCausalLM/model_type: qwen3_5_moe_text— the same GDN-hybrid MoE backbone we already run token-exact (315/315 on Qwen3.6-35B-A3B). Every structural knob matches:head_dim256,linear_key/value_head_dim128,linear_num_key_heads16,full_attention_interval4,attn_output_gatetrue,partial_rotary_factor0.25,rope_theta1e7,mtp_num_hidden_layers1, and the same tokenizer (vocab_size248320). The deltas are pure scale (hidden 2048->8192, layers 40->92, experts 256->512, top-k 8->10, moe/shared intermediate 512->2048, linear V-heads 32->128), all config-driven.Two things block loading it:
1. The architecture string is unregistered.
ModelRegistry::Resolveis an exact string match with no aliasing (src/vllm/model_executor/models/model_registry.cpp:217-231); we register onlyQwen3_5MoeForConditionalGeneration(qwen3_5_moe.cpp:215) andQwen3_5ForConditionalGeneration(qwen3_5_dense.cpp:243). A text-only config falls through toRaiseForUnsupported.2. The loader hardcodes the VL weight prefix.
qwen3_5_weights.cpp:560,632,633,659(andqwen3_5_dense_weights.cpp, 3 sites) look upmodel.language_model.*. Verified against the real checkpoints:model.language_model.embed_tokens.weightmodel.embed_tokens.weightmodel.language_model.layers.0.linear_attn.*model.layers.0.linear_attn.*...mlp.experts.gate_up_proj(3D stacked)...mlp.experts.gate_up_proj(3D stacked)lm_head.weightlm_head.weightThe tensor names are identical modulo the prefix — same 3D-stacked experts, same
shared_expert_gate, same top-levellm_head. So the existing loader is correct once the prefix is tolerant.Upstream solves exactly this with a mapper on the text-only base class:
Qwen3_5MoeForCausalLMis a thin text-only class over the same backbone (qwen3_5.py:443-449), andQwen3_5ForCausalLMispassover the shared base (:439).Ahead-of-pin, and stated as such. Our parity pin is
555967922, whose registry has only theForConditionalGenerationentries. The text-only arms were added upstream by PR #50210 /ad5d29db7("[Model] Support Qwen3.5 text-only dense and MoE models"), which is post-pin. This is therefore a deliberate forward port, not a mirror of the pin.We cannot gate it on our hardware, and that is not hidden. 2.4T bf16 is ~4.8 TB; the only other released variant is
Qwen/Qwen3.8-2.4T-A95B-FP8at ~2.4 TB. GB10 has 128 GB unified, and no smaller Qwen3.8 sibling exists. So there is no token-exact oracle run for the 2.4T checkpoint. What IS gateable: config resolution, architecture dispatch, weight-name mapping, and byte-identical inertness of the existing 27B/35B/Coder gates. The run gate stays explicitly OWED and the row must not claim DONE on the 3.8 checkpoint.