{"record":{"id":"8a95a6a6f3488fdb","repo":"invoke-ai/InvokeAI","slug":"got-params-axes-dim-but-expected-positional-dim","errorCode":null,"errorMessage":"Got {params.axes_dim} but expected positional dim {pe_dim}","messagePattern":"Got (.+?) but expected positional dim (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/flux/controlnet/instantx_controlnet_flux.py","lineNumber":59,"sourceCode":"    def __init__(self, params: FluxParams, num_control_modes: int | None = None):\n        \"\"\"\n        Args:\n            params (FluxParams): The parameters for the FLUX model.\n            num_control_modes (int | None, optional): The number of controlnet modes. If non-None, then the model is a\n                'union controlnet' model and expects a mode conditioning input at runtime.\n        \"\"\"\n        super().__init__()\n\n        # The following modules mirror the base FLUX transformer model.\n        # -------------------------------------------------------------\n        self.params = params\n        self.in_channels = params.in_channels\n        self.out_channels = self.in_channels\n        if params.hidden_size % params.num_heads != 0:\n            raise ValueError(f\"Hidden size {params.hidden_size} must be divisible by num_heads {params.num_heads}\")\n        pe_dim = params.hidden_size // params.num_heads\n        if sum(params.axes_dim) != pe_dim:\n            raise ValueError(f\"Got {params.axes_dim} but expected positional dim {pe_dim}\")\n        self.hidden_size = params.hidden_size\n        self.num_heads = params.num_heads\n        self.pe_embedder = EmbedND(dim=pe_dim, theta=params.theta, axes_dim=params.axes_dim)\n        self.img_in = nn.Linear(self.in_channels, self.hidden_size, bias=True)\n        self.time_in = MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size)\n        self.vector_in = MLPEmbedder(params.vec_in_dim, self.hidden_size)\n        self.guidance_in = (\n            MLPEmbedder(in_dim=256, hidden_dim=self.hidden_size) if params.guidance_embed else nn.Identity()\n        )\n        self.txt_in = nn.Linear(params.context_in_dim, self.hidden_size)\n\n        self.double_blocks = nn.ModuleList(\n            [\n                DoubleStreamBlock(\n                    self.hidden_size,\n                    self.num_heads,\n                    mlp_ratio=params.mlp_ratio,\n                    qkv_bias=params.qkv_bias,","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/flux/controlnet/instantx_controlnet_flux.py#L41-L77","documentation":"InstantXControlNetFlux.__init__ computes the positional-embedding dimension as hidden_size // num_heads and requires the sum of params.axes_dim (the RoPE per-axis dims) to equal that value. If the FluxParams config supplies an axes_dim list whose elements don't sum to pe_dim, the model would be built with an inconsistent rotary embedding, so it refuses to construct. This is a config-integrity check mirroring the upstream flux reference model.","triggerScenarios":"Constructing InstantXControlNetFlux(params=FluxParams(...)) where sum(params.axes_dim) != params.hidden_size // params.num_heads — e.g. custom hidden_size/num_heads copied from another checkpoint while keeping default axes_dim=[16,56,56] (sums to 128).","commonSituations":"Adapting the ControlNet to a non-standard Flux variant or a distilled model with different head counts; hand-editing FluxParams; porting configs between Flux schnell/dev and XLabs/InstantX checkpoints where pe layouts differ.","solutions":["Set params.axes_dim so its elements sum to params.hidden_size // params.num_heads (default Flux: hidden_size=3072, num_heads=24 → pe_dim=128, axes_dim=[16,56,56]).","Adjust num_heads to a divisor of hidden_size that makes hidden_size/num_heads equal your axes_dim sum.","Restore the default FluxParams values matching the checkpoint you loaded.","Verify the checkpoint's config JSON (hidden_size, num_heads, axes_dim) matches what you pass in."],"exampleFix":"// before\nparams = FluxParams(in_channels=64, hidden_size=2048, num_heads=24, axes_dim=[16,56,56], ...)  # sum=128 != 2048/24\n// after\nparams = FluxParams(in_channels=64, hidden_size=3072, num_heads=24, axes_dim=[16,56,56], ...)  # 3072/24=128 == sum(axes_dim)","handlingStrategy":"validation","validationCode":"pe_dim = params.hidden_size // params.num_heads\nassert params.hidden_size % params.num_heads == 0, \"hidden_size must be divisible by num_heads\"\nassert sum(params.axes_dim) == pe_dim, f\"sum(axes_dim)={sum(params.axes_dim)} != pe_dim={pe_dim}\"","typeGuard":"def is_valid_flux_params(p) -> bool:\n    return p.hidden_size % p.num_heads == 0 and sum(p.axes_dim) == p.hidden_size // p.num_heads","tryCatchPattern":"try:\n    controlnet = InstantXControlNetFlux(params=params)\nexcept ValueError as e:\n    if \"expected positional dim\" in str(e):\n        pe_dim = params.hidden_size // params.num_heads\n        params = replace(params, axes_dim=scale_axes_dim(params.axes_dim, pe_dim))\n        controlnet = InstantXControlNetFlux(params=params)\n    else:\n        raise","preventionTips":["Keep FluxParams sourced from the checkpoint's config file, never hand-typed.","Add an assertion that sum(axes_dim) == hidden_size // num_heads in your config loader.","Remember the canonical values: hidden_size=3072, num_heads=24, axes_dim=[16,56,56]."],"tags":["config","validation","flux","controlnet"],"backgroundTag":"axes-dim-positional-dim-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}