{"record":{"id":"e9db1968a5b01a8c","repo":"immich-app/immich","slug":"unsupported-model-file-type-model-path-suffix","errorCode":null,"errorMessage":"Unsupported model file type: {model_path.suffix}","messagePattern":"Unsupported model file type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"machine-learning/immich_ml/models/base.py","lineNumber":119,"sourceCode":"                    f\"for '{self.model_name}'. Removing file and replacing with a directory.\"\n                ),\n            )\n            self.cache_dir.unlink()\n        self.cache_dir.mkdir(parents=True, exist_ok=True)\n\n    def _make_session(self, model_path: Path) -> ModelSession:\n        if not model_path.is_file():\n            raise FileNotFoundError(f\"Model file not found: {model_path}\")\n\n        match model_path.suffix:\n            case \".armnn\":\n                session: ModelSession = AnnSession(model_path)\n            case \".onnx\":\n                session = OrtSession(model_path)\n            case \".rknn\":\n                session = rknn.RknnSession(model_path)\n            case _:\n                raise ValueError(f\"Unsupported model file type: {model_path.suffix}\")\n        return session\n\n    def model_path_for_format(self, model_format: ModelFormat) -> Path:\n        model_path_prefix = rknn.model_prefix if model_format == ModelFormat.RKNN else None\n        if model_path_prefix:\n            return self.model_dir / model_path_prefix / f\"model.{model_format}\"\n        return self.model_dir / f\"model.{model_format}\"\n\n    @property\n    def model_dir(self) -> Path:\n        return self.cache_dir / self.model_type.value\n\n    @property\n    def model_path(self) -> Path:\n        return self.model_path_for_format(self.model_format)\n\n    @property\n    def model_task(self) -> ModelTask:","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/machine-learning/immich_ml/models/base.py#L101-L137","documentation":"Raised by the default branch of the match/case in _make_session. Only the suffixes .armnn, .onnx and .rknn are mapped to a session class; any other suffix (including uppercase variants like .ONNX, or .tflite, .pt, .safetensors) is rejected. The suffix comes from model_path_for_format() which builds f\"model.{model_format}\", so it reflects the ModelFormat enum value.","triggerScenarios":"Passing a model_format whose string value is not one of armnn/onnx/rknn (a custom/typo enum member), or pointing _make_session at a file whose extension is not in the handled set. Also hit if model_path_for_format is overridden or a path with an unexpected suffix is passed directly to _make_session.","commonSituations":"Extending ModelFormat with a new format (e.g. TFLITE, TORCH) without adding a matching case in _make_session; case-sensitivity issues where the file is named model.ONNX; corrupt or renamed model files in the cache; pointing the loader at a raw PyTorch checkpoint.","solutions":["Check model_path.suffix in the error and confirm it is exactly '.armnn', '.onnx', or '.rknn' (lowercase).","If you intended a new format, add a matching case in _make_session and a corresponding session class.","Rename the cached file to the correct lowercase extension, or call clear_cache() and re-download.","Verify the ModelFormat enum value used matches the suffix of the file snapshot_download actually produced."],"exampleFix":"# before\nclass ModelFormat(str, Enum):\n    ONNX = 'onnx'\n    ARMNN = 'armnn'\n    RKNN = 'rknn'\n    TFLITE = 'tflite'   # new member, no case in _make_session -> ValueError\n\n# after\nmatch model_path.suffix:\n    case '.armnn':\n        session = AnnSession(model_path)\n    case '.onnx':\n        session = OrtSession(model_path)\n    case '.rknn':\n        session = rknn.RknnSession(model_path)\n    case '.tflite':\n        session = TfliteSession(model_path)\n    case _:\n        raise ValueError(f\"Unsupported model file type: {model_path.suffix}\")","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nSUPPORTED_SUFFIXES = {'.armnn', '.onnx', '.rknn'}\n\ndef validate_model_suffix(path: Path) -> None:\n    if path.suffix not in SUPPORTED_SUFFIXES:\n        raise ValueError(\n            f\"Model suffix {path.suffix!r} unsupported; expected one of {sorted(SUPPORTED_SUFFIXES)}\"\n        )\n\n# call before constructing the session:\nvalidate_model_suffix(model_path)","typeGuard":"from pathlib import Path\n\nSUPPORTED_SUFFIXES = {'.armnn', '.onnx', '.rknn'}\n\ndef is_supported_model_suffix(path: Path) -> bool:\n    return isinstance(path, Path) and path.suffix in SUPPORTED_SUFFIXES","tryCatchPattern":"try:\n    session = model._make_session(model_path)\nexcept ValueError as e:\n    if 'Unsupported model file type' in str(e):\n        raise ValueError(f\"Refusing to load {model_path}: convert to .onnx/.armnn/.rknn first\") from e\n    raise","preventionTips":["When adding a ModelFormat enum member, add the matching case in _make_session in the same commit.","Use lowercase suffixes consistently when naming cached files; treat uppercase as a bug.","Unit-test _make_session with each supported suffix and one unsupported suffix to lock the contract."],"tags":["model-loading","validation","enum","file-extension"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}