{"record":{"id":"b001fac9dff5078b","repo":"unslothai/unsloth","slug":"activation-rotation-target-fqn-r-is-not-an-nn-li","errorCode":null,"errorMessage":"activation rotation target {fqn!r} is not an nn.Linear","messagePattern":"activation rotation target (.+?) is not an nn\\.Linear","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/diffusion_convrot.py","lineNumber":360,"sourceCode":"    problem = rotation_metadata_error(metadata)\n    if problem:\n        raise ValueError(problem)\n\n    from torch import nn\n\n    group_size = int(metadata[ROTATION_GROUP_KEY])\n    fqns = list(metadata[ROTATION_FQNS_KEY])\n    modules = dict(transformer.named_modules())\n    missing = [fqn for fqn in fqns if fqn not in modules]\n    if missing:\n        raise ValueError(\n            f\"activation rotation names {len(missing)} fqn(s) this model does not have \"\n            f\"(e.g. {missing[0]!r}); the checkpoint and this build disagree about the model\"\n        )\n    for fqn in fqns:\n        module = modules[fqn]\n        if not isinstance(module, nn.Linear):\n            raise ValueError(f\"activation rotation target {fqn!r} is not an nn.Linear\")\n        if is_rotated_linear(module):\n            raise ValueError(f\"activation rotation target {fqn!r} is already rotated\")\n        if module.in_features % group_size:\n            raise ValueError(\n                f\"activation rotation target {fqn!r} has in_features {module.in_features}, \"\n                f\"which the recorded group {group_size} does not divide\"\n            )\n    # Every target is validated before ANY is swapped. A partial install is the one outcome worse\n    # than either end state: the rotated half still renders, just wrongly, so there is nothing to\n    # notice and nothing to fall back from.\n    for fqn in fqns:\n        _install_rotation(modules[fqn], group_size)\n    try:\n        setattr(\n            transformer,\n            CONVROT_ATTR,\n            {\"kind\": CONVROT_KIND, \"group\": group_size, \"linears\": len(fqns)},\n        )","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/diffusion_convrot.py#L342-L378","documentation":"At load time, a fqn recorded in the checkpoint's rotation metadata resolves to a module that is not an nn.Linear in this model. Only plain Linears can host the online rotation, and every target is validated before any swap so a partial install cannot happen.","triggerScenarios":"apply_activation_rotation on a model where a recorded fqn now names an Embedding, LayerNorm, fused module, or Linear subclass wrapper that fails isinstance(module, nn.Linear); typical when padding (apply_small_m_padding) or another transform reparented modules first, or the architecture changed.","commonSituations":"Calling apply_activation_rotation AFTER apply_small_m_padding (the docstring requires the reverse order, because padding reparents Linears under a wrapper); architecture revision replacing a Linear with a fused implementation; loading the meta-retry path that rebuilt modules differently.","solutions":["Call apply_activation_rotation after load_state_dict but BEFORE apply_small_m_padding, as documented","Ensure base model and rotation metadata come from the same architecture revision","Fall back to the dense checkpoint if the build genuinely differs"],"exampleFix":"# before\napply_small_m_padding(transformer, 64)\napply_activation_rotation(transformer, metadata)  # fqns now name wrappers\n\n# after\napply_activation_rotation(transformer, metadata)  # immediately after load_state_dict\napply_small_m_padding(transformer, 64)","handlingStrategy":"validation","validationCode":"from torch import nn\n\ndef rotation_targets_ok(transformer, fqns) -> bool:\n    mods = dict(transformer.named_modules())\n    return all(fqn in mods and isinstance(mods[fqn], nn.Linear) for fqn in fqns)","typeGuard":"from torch import nn\n\ndef is_rotation_target(module) -> bool:\n    return isinstance(module, nn.Linear)  # wrappers created by padding fail this by design","tryCatchPattern":"try:\n    apply_activation_rotation(transformer, metadata)\nexcept ValueError as e:\n    raise CheckpointRefused(str(e)) from e  # loader converts to dense fallback","preventionTips":["Order the load path exactly as documented: load_state_dict -> apply_activation_rotation -> apply_small_m_padding","Do not insert extra module-wrapping transforms between load and rotation","Re-check targets after any meta-device retry rebuilds modules"],"tags":["convrot","ordering","fqn","quantization"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}