{"record":{"id":"eb3a9030e1b15bf8","repo":"unslothai/unsloth","slug":"activation-rotation-target-fqn-r-has-in-features","errorCode":null,"errorMessage":"activation rotation target {fqn!r} has in_features {module.in_features}, which the recorded group {group_size} does not divide","messagePattern":"activation rotation target (.+?) has in_features (.+?), which the recorded group (.+?) does not divide","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/diffusion_convrot.py","lineNumber":364,"sourceCode":"    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        )\n    except Exception:  # noqa: BLE001 -- the marker is a diagnostic, never the mechanism\n        pass\n    if logger is not None:\n        logger.info(","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/diffusion_convrot.py#L346-L382","documentation":"At load time, a recorded target Linear's in_features is not divisible by the group size recorded in checkpoint metadata. The online rotation reshapes the last dimension into blocks of group_size, so a non-divisible feature count is structurally impossible to rotate and is refused before any swap (all targets are validated first).","triggerScenarios":"Loading rotated checkpoint metadata (group_size G) onto a model whose Linear widths are not multiples of G — e.g. group 64 recorded but this revision of the model has a projection with 70/96/11008-vs-group mismatch; or small-m padding was skipped before the offline build.","commonSituations":"Architecture revision changed hidden sizes after the checkpoint was rotated; checkpoint built with padding applied but loaded against unpadded weights; group size tuned on one model and reused on another.","solutions":["Load the exact base model the checkpoint was built from (same hidden sizes)","Re-run the offline rotation with a group that divides every target's in_features","Ensure apply_small_m_padding ran during the build so widths are multiples of the group, and that the loader reproduces the same padding order"],"exampleFix":"# before\napply_activation_rotation(transformer, metadata)  # group 64, layer in_features=70\n\n# after\n# rebuild checkpoint with a group that divides every target:\napply_rotation(transformer, fqns, group_size=next(g for g in (64,16,4) if all(m.in_features % g == 0 for m in targets)))","handlingStrategy":"validation","validationCode":"def groups_fit(transformer, fqns, group_size: int) -> bool:\n    mods = dict(transformer.named_modules())\n    return all(mods[fqn].in_features % group_size == 0 for fqn in fqns)","typeGuard":null,"tryCatchPattern":"try:\n    apply_activation_rotation(transformer, metadata)\nexcept ValueError as e:\n    return dense_fallback(str(e))  # checkpoint widths and model disagree; refuse the checkpoint","preventionTips":["Build rotated checkpoints with a group that divides every target's in_features","Apply the same padding (apply_small_m_padding) at build and load time, in the documented order","Record hidden-size-relevant model revisions in metadata and match them at load"],"tags":["convrot","shape-mismatch","checkpoint-mismatch","quantization"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}