{"record":{"id":"c179d576b9ec4d81","repo":"invoke-ai/InvokeAI","slug":"latent-channels-latent-channels-do-not-match-bac","errorCode":null,"errorMessage":"latent channels={latent_channels} do not match backbone {expected_base}","messagePattern":"latent channels=(.+?) do not match backbone (.+?)","errorType":"exception","errorClass":"NotAMatchError","httpStatus":null,"severity":"info","filePath":"invokeai/backend/model_manager/configs/pid_decoder.py","lineNumber":358,"sourceCode":"        four of the five classes are supposed to say about every valid checkpoint. The reasons that\n        would rule out all five are raised in ``from_model_on_disk`` before this runs.\n\n        The latent channel count is authoritative and is the only thing separating SDXL (4ch) and\n        FLUX.2 (128ch) from the 16ch family. FLUX.1, SD3 and Qwen-Image are architecturally\n        identical, so within that family, in order of how much the evidence can be trusted:\n\n        - an explicit ``base`` override wins outright. ``raise_for_override_fields`` has already\n          validated it against this class's ``Literal``, so it names exactly one of the five, and\n          whoever set it knows more than a filename anyone can write;\n        - failing that, a name component naming exactly one of the three decides;\n        - failing that, the family defaults to FLUX.1.\n        \"\"\"\n        expected_base = cls.model_fields[\"base\"].default\n        # Guaranteed present: an unsupported channel count was rejected outright before this ran.\n        candidate_bases = _LATENT_CHANNELS_TO_BASES[latent_channels]\n\n        if expected_base not in candidate_bases:\n            raise NotAMatchError(f\"latent channels={latent_channels} do not match backbone {expected_base}\")\n        if len(candidate_bases) == 1 or had_base_override:\n            return\n\n        # A name pointing outside the family — a 16-channel file called \"sdxl\" — contradicts the\n        # weights and is discarded rather than obeyed. Obeying it would have all three 16ch classes\n        # reject the file, leaving a perfectly good decoder to the `Unknown_Config` fallback.\n        if named_base not in candidate_bases:\n            named_base = None\n\n        if named_base is None:\n            if expected_base is not BaseModelType.Flux:\n                raise NotAMatchError(\"ambiguous 16-channel PiD checkpoint; defaulting to FLUX.1\")\n            return\n        if named_base is not expected_base:\n            raise NotAMatchError(f\"name indicates {named_base}, not {expected_base}\")\n\n\nclass PiDDecoder_Checkpoint_FLUX_Config(PiDDecoder_Checkpoint_Config_Base, Config_Base):","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/pid_decoder.py#L340-L376","documentation":"Each PiD config class pins `base` to one backbone. `_validate_base` compares the class's pinned backbone against the set of backbones compatible with the checkpoint's latent channel count; an SDXL config examining a 16-channel file (or FLUX.2 examining 16ch, etc.) raises `NotAMatchError`, which just means 'not this backbone' while another class claims the file.","triggerScenarios":"Raised inside `_validate_base` when `expected_base not in _LATENT_CHANNELS_TO_BASES[latent_channels]` — e.g. the SDXL config class evaluates a 16-channel FLUX-family checkpoint during multi-class identification.","commonSituations":"Normal during identification of any 16ch (FLUX.1/SD3/Qwen-Image) or other-family checkpoint: four of the five classes will raise this by design. Only a problem if it surfaces as the final error, i.e. no class matched at all.","solutions":["If identification ultimately fails, pass an explicit `base` override matching the checkpoint's true backbone","Verify the checkpoint's latent channel count (dim 1 of `lq_proj.latent_proj.0.weight`) and use the matching config (4=SDXL, 16=FLUX.1/SD3/Qwen-Image, 128=FLUX.2)","If this error is the only one raised and the file is valid, ensure you are on a recent InvokeAI version where another class will claim it"],"exampleFix":"// before\ninstall(path)  # auto-detect\n// after\ninstall(path, base='flux')  # for a 16-channel FLUX.1 decoder","handlingStrategy":"try-catch","validationCode":"import torch\nsd = torch.load(ckpt_path, map_location='cpu')\nkey = next(k for k in sd if 'lq_proj' in k and 'latent_proj' in k)\nch = sd[key].shape[1]\nbase = {4: 'sdxl', 16: 'flux', 128: 'flux2'}.get(ch)\n# install with base=base (for 16ch, pick flux/sd3/qwen-image explicitly)","typeGuard":null,"tryCatchPattern":"try:\n    install_model(path)\nexcept NotAMatchError:\n    pass  # expected during identification: another backbone class claims the file","preventionTips":["Pass an explicit `base` override matching the checkpoint's backbone","Remember this error is normal when other config classes evaluate the file","Read dim 1 of lq_proj.latent_proj.0.weight to learn the true backbone (4=SDXL, 16=16ch family, 128=FLUX.2)"],"tags":["model-identification","backbone-mismatch","expected-behavior"],"backgroundTag":"model-not-a-match","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}