sgl-project/sglang · error · ValueError
{name} must stay fp32 with curve AdaLN, got {param.dtype}.
Error message
{name} must stay fp32 with curve AdaLN, got {param.dtype}. What it means
When curve AdaLN is active (adaln_t_table present), every parameter under a '.adaln_proj.linear.' submodule must stay fp32 because the curve interpolation math is dtype-sensitive. post_load_weights scans named_parameters and raises on any such parameter that was downcast during loading.
Source
Thrown at python/sglang/multimodal_gen/runtime/models/dits/minimax_h3.py:2079
if self.adaln_t_table is not None:
fp32_param_names = [
name
for name in fp32_param_names
if not name.startswith("time_embedder.")
]
fp32_param_names.append("adaln_t_table")
if self.adaln_basis is not None:
fp32_param_names.extend(("adaln_basis", "adaln_mean"))
for name in fp32_param_names:
param = self.get_parameter(name)
if param.dtype != _FP32_DTYPE:
raise ValueError(
f"{name} must stay fp32 after load, got {param.dtype}."
)
if self.adaln_t_table is not None:
for name, param in self.named_parameters():
if ".adaln_proj.linear." in name and param.dtype != _FP32_DTYPE:
raise ValueError(
f"{name} must stay fp32 with curve AdaLN, got {param.dtype}."
)
# assign=True loading may re-register this persistent buffer as a parameter
rope_inv_freq = self.rope.inv_freq
if rope_inv_freq.dtype != _FP32_DTYPE:
raise ValueError(
f"rope.inv_freq must stay fp32 after load, got {rope_inv_freq.dtype}."
)
if self.adaln_cache is not None:
self.adaln_cache.load(self.video_patch_proj.weight.device)
def _time_embedding(self, timesteps: torch.Tensor) -> torch.Tensor:
if self.adaln_t_table is None:
assert self.time_embedder is not None
return self.time_embedder(timesteps)
grid = self.adaln_t_table.shape[0]
position = timesteps.to(_FP32_DTYPE).clamp(0, 1) * (grid - 1)View on GitHub (pinned to 0132848349)
Solutions
- Exclude adaln_proj.linear.* tensors from any dtype casting in your conversion/loading pipeline
- Re-save the checkpoint keeping adaln_proj weights in fp32
- Load in the native checkpoint dtype and cast only compute weights afterwards
Example fix
# before model.to(torch.bfloat16); model.load_state_dict(sd, assign=True) # after model.load_state_dict(sd, assign=True) model._keep_adaln_fp32() # or cast everything except adaln_proj/adaln tables
Defensive patterns
Strategy: type-guard
Validate before calling
for name, p in model.named_parameters():
if ".adaln_proj.linear." in name:
assert p.dtype == torch.float32, (name, p.dtype) Type guard
def adaln_proj_fp32(model) -> bool:
return all(p.dtype == torch.float32
for n, p in model.named_parameters()
if ".adaln_proj.linear." in n) Try / catch
try:
model.post_load_weights()
except ValueError:
with torch.no_grad():
for n, p in model.named_parameters():
if ".adaln_proj.linear." in n:
p.data = p.data.float()
model.post_load_weights() Prevention
- Cast compute weights only after loading
- Keep curve-AdaLN checkpoints' adaln_proj tensors fp32
When it happens
Trigger: Loading a curve-AdaLN checkpoint where adaln_proj.linear.weight/bias arrived as bf16/fp16 — usually from a global dtype cast in the loader or a mixed-precision checkpoint.
Common situations: model.to(torch.bfloat16) before load; converters that cast all linear weights; fp16-serialized checkpoints.
Related errors
- {name} must stay fp32 after load, got {param.dtype}.
- rope.inv_freq must stay fp32 after load, got {rope_inv_freq.
- Eagle3 MLA draft post_load_weights only supports float dtype
- Reserved serve backend names cannot be used: {names}
- Unsupported type {type(data)}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/8d2c3b482d0db10a.
Report an issue: GitHub.