unslothai/unsloth · error · ValueError
cannot rotate {fqn!r}: not an nn.Linear on this model
Error message
cannot rotate {fqn!r}: not an nn.Linear on this model What it means
During offline weight rotation, one of the requested fully-qualified module names resolved to something that is not an nn.Linear (or to nothing the isinstance check accepts). Only plain Linears can be block-rotated, so the builder refuses rather than rotating a wrong module type.
Source
Thrown at studio/backend/core/inference/diffusion_convrot.py:315
transformer: Any,
fqns: Iterable[str],
group_size: int = DEFAULT_CONVROT_GROUPSIZE,
) -> tuple[str, ...]:
"""OFFLINE half: rotate the weights of ``fqns`` and install the online rotation on each.
Call BEFORE ``quantize_``, on a dense model: the whole point is that the quantizer sees the
flatter distribution. Returns the fqns rotated, in the order given. Raises on anything it
cannot rotate, so a builder can never record a set larger than the one it actually applied."""
from torch import nn
if not is_power_of_four(group_size):
raise ValueError(f"ConvRot group size must be a power of 4, got {group_size!r}")
modules = dict(transformer.named_modules())
rotated: list[str] = []
for fqn in fqns:
module = modules.get(fqn)
if not isinstance(module, nn.Linear):
raise ValueError(f"cannot rotate {fqn!r}: not an nn.Linear on this model")
rotate_convrot_weight_(module, group_size)
_install_rotation(module, group_size)
rotated.append(fqn)
return tuple(rotated)
def apply_activation_rotation(
transformer: Any,
metadata: Any,
*,
logger: Any = None,
) -> tuple[str, ...]:
"""ONLINE half: install the input rotation on exactly the fqns ``metadata`` records.
Returns the fqns rotated, or ``()`` when ``metadata`` declares no rotation -- the plain
artifacts, which have to be left exactly as they are. RAISES on any other outcome: an
unusable contract, an fqn this model does not have, a target that is not a Linear, an
``in_features`` the recorded group does not divide, or a Linear already rotated. The prequantView on GitHub (pinned to 203007d190)
Solutions
- Print dict(transformer.named_modules()) and correct the fqn to name an actual nn.Linear
- Regenerate the fqn list from the live model (filter isinstance(module, nn.Linear)) instead of hardcoding it
- If the layer genuinely changed type in this architecture, remove it from the rotation set
Example fix
# before apply_rotation(transformer, ["model.layers.0.mlp"], 64) # module is the MLP block # after apply_rotation(transformer, ["model.layers.0.mlp.down_proj"], 64) # an nn.Linear
Defensive patterns
Strategy: type-guard
Validate before calling
from torch import nn
def linear_fqns(transformer) -> list[str]:
return [fqn for fqn, m in transformer.named_modules() if isinstance(m, nn.Linear)] Type guard
from torch import nn
def is_plain_linear(module) -> bool:
"""True only for modules the offline rotation accepts."""
return isinstance(module, nn.Linear) Try / catch
try:
apply_rotation(transformer, fqns, group_size)
except ValueError as e:
raise BuildError(str(e)) from e # regenerate the fqn list from this model, do not edit by hand Prevention
- Generate fqn lists programmatically from named_modules() on the exact model being rotated
- Re-generate the list whenever the model architecture revision changes
- Prefer raising over partial rotation: the API already returns only the fqns it rotated
When it happens
Trigger: Passing an fqn naming a Conv1d, Embedding, LayerNorm, or a wrapper/override of Linear that fails isinstance(module, nn.Linear); also an fqn that resolves to None is caught by the same check. Happens when the fqn list was written for a different architecture revision.
Common situations: Model architecture updated and a target layer became a fused/quantized wrapper or was renamed; fqn list generated by an older naming pass (e.g. missing or extra '.'); targeting attention projections that this revision implements as a single bundled module.
Related errors
- activation rotation names {len(missing)} fqn(s) this model d
- activation rotation target {fqn!r} is not an nn.Linear
- ConvRot group size must be a power of 4, got {size}
- features {features} not divisible by ConvRot group {group_si
- in_features {in_features} is not divisible by the ConvRot gr
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/8d7dbec8b5d1d65a.
Report an issue: GitHub.