{"record":{"id":"3615f2051f499b43","repo":"invoke-ai/InvokeAI","slug":"a-submodel-type-tokenizer-or-textencoder-must-be","errorCode":null,"errorMessage":"A submodel type (Tokenizer or TextEncoder) must be provided.","messagePattern":"A submodel type \\(Tokenizer or TextEncoder\\) must be provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/load/model_loaders/wan.py","lineNumber":565,"sourceCode":"@ModelLoaderRegistry.register(base=BaseModelType.Any, type=ModelType.WanT5Encoder, format=ModelFormat.WanT5Encoder)\nclass WanT5EncoderLoader(ModelLoader):\n    \"\"\"Loader for the standalone Wan UMT5-XXL encoder.\n\n    Accepts two on-disk layouts:\n    1. Parent dir with ``text_encoder/`` (and typically ``tokenizer/``) subdirs —\n       what ``Wan-AI/Wan2.2-T2V-A14B::text_encoder+tokenizer`` produces.\n    2. A flat ``text_encoder/`` folder with ``config.json`` declaring\n       ``model_type: umt5`` directly at the root. In this case the tokenizer\n       is loaded from the same folder via ``AutoTokenizer.from_pretrained``.\n    \"\"\"\n\n    def _load_model(\n        self,\n        config: AnyModelConfig,\n        submodel_type: Optional[SubModelType] = None,\n    ) -> AnyModel:\n        if submodel_type is None:\n            raise ValueError(\"A submodel type (Tokenizer or TextEncoder) must be provided.\")\n\n        root = Path(config.path)\n        nested_text_encoder = root / \"text_encoder\"\n        nested_tokenizer = root / \"tokenizer\"\n\n        if submodel_type == SubModelType.TextEncoder:\n            from transformers import UMT5EncoderModel\n\n            target = nested_text_encoder if nested_text_encoder.exists() else root\n            return UMT5EncoderModel.from_pretrained(\n                str(target),\n                torch_dtype=torch.bfloat16,\n                local_files_only=True,\n            )\n        if submodel_type == SubModelType.Tokenizer:\n            from transformers import AutoTokenizer\n\n            # Prefer a sibling tokenizer/ directory; fall back to the encoder dir","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/load/model_loaders/wan.py#L547-L583","documentation":"WanModelLoader._load_model loads submodels (tokenizers, text encoders) of a Wan pipeline by delegating per-submodel, and the submodel_type argument tells it which piece to fetch. The library raises ValueError when submodel_type is None because there is no sensible default: a loader that receives no submodel type cannot know whether to return the Tokenizer or the TextEncoder. This indicates a loader orchestration bug or a caller invoking _load_model directly without the required argument.","triggerScenarios":"Calling WanModelLoader._load_model(config) with submodel_type omitted/None, or a ModelLoaderRegistry/pipeline-load path that fails to pass SubModelType when dispatching submodel loads for Wan models.","commonSituations":"Custom loader code calling _load_model directly for the main model; a refactor that dropped the submodel_type kwarg; a generic loading helper written for single-file models reused on diffusers-style Wan folders where submodels are loaded separately.","solutions":["Pass an explicit submodel_type, e.g. loader._load_model(config, SubModelType.Tokenizer) or SubModelType.TextEncoder.","Load the main Wan pipeline through the standard ModelManager/ModelLoaderRegistry API instead of calling _load_model directly so submodels are dispatched correctly.","If you maintain the loader, raise earlier with a clearer message or default the dispatch in the caller that enumerates submodels."],"exampleFix":"// before\nmodel = loader._load_model(config)\n\n// after\nfrom invokeai.backend.model_manager.taxonomy import SubModelType\nmodel = loader._load_model(config, SubModelType.TextEncoder)","handlingStrategy":"validation","validationCode":"if submodel_type is None:\n    raise ValueError(\"submodel_type is required for Wan submodel loading; pass SubModelType.Tokenizer or SubModelType.TextEncoder\")","typeGuard":"def has_submodel_type(st: SubModelType | None) -> bool:\n    return st is not None","tryCatchPattern":"try:\n    model = loader._load_model(config, submodel_type)\nexcept ValueError as e:\n    if \"submodel type\" in str(e):\n        model = loader._load_model(config, SubModelType.TextEncoder)\n    else:\n        raise","preventionTips":["Never call loader._load_model directly; go through ModelLoaderRegistry/ModelManager so submodel_type is always supplied.","When writing generic loader helpers, make submodel_type a required parameter for diffusers-style pipelines.","Add a unit test asserting the loader raises only for genuinely unknown submodel types."],"tags":["python","valueerror","model-loading","invalid-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}