{"record":{"id":"d66dbca28d9dd603","repo":"invoke-ai/InvokeAI","slug":"pid-checkpoint-has-channels-latent-channels-no","errorCode":null,"errorMessage":"PiD checkpoint has {channels} latent channels; no supported backbone uses this (supported: 4 for SDXL, 16 for FLUX.1/SD3/Qwen-Image, 128 for FLUX.2)","messagePattern":"PiD checkpoint has (.+?) latent channels; no supported backbone uses this \\(supported: 4 for SDXL, 16 for FLUX\\.1/SD3/Qwen-Image, 128 for FLUX\\.2\\)","errorType":"exception","errorClass":"InvalidMatchError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/configs/pid_decoder.py","lineNumber":122,"sourceCode":"        )\n\n\ndef _raise_if_no_backbone_can_accept(shapes: _Shapes) -> None:\n    \"\"\"Reject a PiD decoder that none of the five backbone configs could ever claim.\n\n    The counterpart to `_validate_base`, and the reason the two are separate. `_validate_base` decides\n    *which* backbone a checkpoint belongs to and says \"not this one\" with `NotAMatchError` — four of\n    the five classes are meant to say exactly that about every valid checkpoint. A rejection here is\n    backbone-independent, so all five would raise it for the same reason, leaving the file with no\n    match at all and letting the factory register it through the `Unknown_Config` fallback: a PiD\n    decoder on record as a model nothing can load. Hence `InvalidMatchError`.\n\n    Runs before the contract check because a decoder for an unsupported backbone would otherwise be\n    reported as a shape mismatch on one weight, which is true and useless.\n    \"\"\"\n    channels = shapes[_LATENT_PROJ_KEY][1]  # type: ignore[index]  # rank checked above\n    if channels not in _LATENT_CHANNELS_TO_BASES:\n        raise InvalidMatchError(\n            f\"PiD checkpoint has {channels} latent channels; no supported backbone uses this \"\n            \"(supported: 4 for SDXL, 16 for FLUX.1/SD3/Qwen-Image, 128 for FLUX.2)\"\n        )\n\n\ndef _and_more(items: list[Any]) -> str:\n    return f\" (+ {len(items) - 5} more)\" if len(items) > 5 else \"\"\n\n\ndef _raise_if_pid_net_contract_unmet(shapes: _Shapes, contract: Mapping[str, tuple[int, ...]]) -> None:\n    \"\"\"Hold the checkpoint to exactly the contract `load_pid_decoder` enforces.\n\n    Checking only the LQ projection accepted a file that carried every LQ weight and none of the 385\n    backbone weights; the loader then refused it. A subset check is not a milder version of the same\n    guarantee — loaders run under `skip_torch_weight_init()`, so a weight the checkpoint does not\n    supply is uninitialised memory rather than a default.\n\n    Missing *and* unexpected keys are fatal here because both are fatal there, which is what makes","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/pid_decoder.py#L104-L140","documentation":"Identification reads dimension 1 of the latent projection weight to learn the backbone's latent channel count. If it is not 4 (SDXL), 16 (FLUX.1/SD3/Qwen-Image), or 128 (FLUX.2), no supported PiD backbone config could ever claim the file, so an `InvalidMatchError` is raised (backbone-independent, preventing a bogus `Unknown_Config` registration).","triggerScenarios":"Installing a PiD checkpoint whose `lq_proj.latent_proj.0.weight` has a channel count outside {4,16,128}; raised from `_raise_if_no_backbone_can_accept` during `from_model_on_disk`.","commonSituations":"Experimental/fine-tuned PiD decoders trained on a different VAE latent space; checkpoints repurposed for other backbones; corrupted or hand-modified weights.","solutions":["Verify the checkpoint was built for one of the supported backbones (SDXL, FLUX.1, FLUX.2, SD3, Qwen-Image) and re-download from nvidia/PiD","Check the file isn't truncated or altered; compare the weight shape against the official release","If it is a custom research decoder for a different latent space, it cannot be used — no code change will help","Confirm you are not renaming/repacking weights that changed the tensor layout"],"exampleFix":null,"handlingStrategy":"validation","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)\nchannels = sd[key].shape[1]\nif channels not in (4, 16, 128):\n    raise SystemExit(f'{channels} latent channels: no supported PiD backbone uses this.')","typeGuard":"def has_supported_latent_channels(sd: dict) -> bool:\n    key = next((k for k in sd if 'lq_proj' in k and 'latent_proj' in k), None)\n    return key is not None and sd[key].ndim == 4 and sd[key].shape[1] in (4, 16, 128)","tryCatchPattern":"try:\n    install_model(path)\nexcept InvalidMatchError as e:\n    if 'latent channels' in str(e):\n        logger.error('Checkpoint is for an unsupported backbone latent space: %s', e)\n    else:\n        raise","preventionTips":["Only download PiD decoders for supported backbones (SDXL, FLUX.1/2, SD3, Qwen-Image)","Verify checksums after download to rule out corruption","Be wary of custom fine-tunes with changed VAE latent spaces"],"tags":["checkpoint","model-loader","shape-mismatch"],"backgroundTag":"model-checkpoint-incompatible","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}