{"record":{"id":"7f3c332e1cd2287f","repo":"immich-app/immich","slug":"model-path-must-be-a-file-with-extension-armnn","errorCode":null,"errorMessage":"model_path must be a file with extension .armnn, .tflite or .onnx","messagePattern":"model_path must be a file with extension \\.armnn, \\.tflite or \\.onnx","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"machine-learning/immich_ml/sessions/ann/loader.py","lineNumber":105,"sourceCode":"        self.ref_count -= 1\n        if self.ref_count <= 0 and self.ann is not None:\n            libann.destroy(self.ann)\n            self.ann = None\n\n    def __del__(self) -> None:\n        if self.ann is not None:\n            libann.destroy(self.ann)\n            self.ann = None\n\n    def load(\n        self,\n        model_path: str,\n        fast_math: bool = True,\n        fp16: bool = False,\n        cached_network_path: str | None = None,\n    ) -> int:\n        if not model_path.endswith((\".armnn\", \".tflite\", \".onnx\")):\n            raise ValueError(\"model_path must be a file with extension .armnn, .tflite or .onnx\")\n        if not exists(model_path):\n            raise ValueError(\"model_path must point to an existing file!\")\n\n        save_cached_network = False\n        if cached_network_path is not None and not exists(cached_network_path):\n            save_cached_network = True\n            # create empty model cache file\n            open(cached_network_path, \"a\").close()\n\n        net_id: int = libann.load(\n            self.ann,\n            model_path.encode(),\n            fast_math,\n            fp16,\n            save_cached_network,\n            cached_network_path.encode() if cached_network_path is not None else None,\n        )\n        if net_id < 0:","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/machine-learning/immich_ml/sessions/ann/loader.py#L87-L123","documentation":"Raised by Ann.load() when the model_path string does not end with .armnn, .tflite, or .onnx. This is a cheap pre-check performed before touching the filesystem. Note that the higher-level _make_session only constructs AnnSession for the .armnn case, so in normal immich-ml flow this branch guards direct callers of Ann.load().","triggerScenarios":"Calling Ann.load() with a Path/string whose suffix is none of .armnn/.tflite/.onnx, e.g. '.rknn', '.pb', '.pt', or a path with no extension. Also triggered by a trailing slash or a path that ends in a directory name.","commonSituations":"Mixing up RKNN and ARMNN model files on a Rockchip board (passing a .rknn file to Ann.load); pointing at a TensorFlow frozen graph (.pb) or PyTorch (.pt) export; copy-paste error in a custom integration that calls Ann.load directly.","solutions":["Check the suffix of the path passed to Ann.load(); it must be one of .armnn, .tflite, .onnx.","Re-export the model to a supported format, or convert it with the Arm NN toolchain.","If you have a .rknn file, use rknn.RknnSession / the RKNN pipeline instead of Ann.load.","Strip any trailing slash or whitespace from the path string before calling load()."],"exampleFix":"# before\nann.load('/models/model.rknn')   # ValueError: extension must be .armnn/.tflite/.onnx\n\n# after\nann.load('/models/model.armnn')\n# or, for a Rockchip model:\nfrom immich_ml.sessions.rknn import RknnSession\nsession = RknnSession(Path('/models/model.rknn'))","handlingStrategy":"validation","validationCode":"ARMNN_SUFFIXES = ('.armnn', '.tflite', '.onnx')\n\ndef validate_armnn_model_path(model_path: str) -> None:\n    if not model_path.endswith(ARMNN_SUFFIXES):\n        raise ValueError(\n            f\"model_path {model_path!r} must end with one of {ARMNN_SUFFIXES}\"\n        )\n\n# call before Ann.load():\nvalidate_armnn_model_path(model_path)","typeGuard":"ARMNN_SUFFIXES = ('.armnn', '.tflite', '.onnx')\n\ndef has_armnn_suffix(model_path: str) -> bool:\n    return isinstance(model_path, str) and model_path.endswith(ARMNN_SUFFIXES)","tryCatchPattern":"try:\n    net_id = ann.load(model_path)\nexcept ValueError as e:\n    if 'extension .armnn' in str(e):\n        raise ValueError(f\"Refusing {model_path}: convert to .armnn/.tflite/.onnx first\") from e\n    raise","preventionTips":["Centralize the supported-suffix tuple as a module constant and reuse it in both the guard and the call site.","For RKNN models, route through RknnSession instead of Ann.load to avoid the suffix mismatch entirely.","Add a unit test that Ann.load rejects every unsupported suffix in your integration."],"tags":["armnn","validation","file-extension"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}