{"record":{"id":"131a0f72a48d0419","repo":"immich-app/immich","slug":"cannot-load-model","errorCode":null,"errorMessage":"Cannot load model!","messagePattern":"Cannot load model!","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"machine-learning/immich_ml/sessions/ann/loader.py","lineNumber":124,"sourceCode":"        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:\n            raise ValueError(\"Cannot load model!\")\n\n        self.input_shapes[net_id] = tuple(\n            self.shape(net_id, input=True, index=i) for i in range(self.tensors(net_id, input=True))\n        )\n        self.output_shapes[net_id] = tuple(\n            self.shape(net_id, input=False, index=i) for i in range(self.tensors(net_id, input=False))\n        )\n        return net_id\n\n    def unload(self, network_id: int) -> None:\n        libann.unload(self.ann, network_id)\n        del self.output_shapes[network_id]\n\n    def execute(self, network_id: int, input_tensors: list[NDArray[np.float32]]) -> list[NDArray[np.float32]]:\n        if not isinstance(input_tensors, list):\n            raise ValueError(\"input_tensors needs to be a list!\")\n        net_input_shapes = self.input_shapes[network_id]\n        if len(input_tensors) != len(net_input_shapes):","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/machine-learning/immich_ml/sessions/ann/loader.py#L106-L142","documentation":"Raised by Ann.load() when the native libann.load() call returns a negative network id. At this point the file exists and has a valid extension, but the Arm NN runtime could not parse/load it. The native return code is negative on any internal failure (corrupt file, unsupported operator, I/O error reading the network, cache deserialization failure).","triggerScenarios":"Passing a truncated or partially-written .armnn/.onnx/.tflite file to libann; a model using ops not supported by the Arm NN version bundled in libann.so; a corrupt cached_network_path that libann tries to deserialize; mismatch between the model format and libann's parser; disk read error during load.","commonSituations":"Interrupted download leaving a half-size model file (passes exists() check but fails to parse); using an ONNX opset newer than Arm NN supports; reusing a cached_network_path produced by a different libann version; bit-rot on the volume holding the model; concurrent writers corrupting the file.","solutions":["Check the file size/hash against the source repo to detect truncation or corruption; re-download if mismatched.","Delete any cached_network_path you passed in (or let save_cached_network recreate it) so a stale cache is not deserialized.","Inspect Arm NN / libann logs (raise Ann log_level to 1 or 0) for the specific parser error, then re-export the model avoiding the unsupported op.","Re-export the ONNX model to an opset/version Arm NN supports and retry.","Ensure no other process is writing the model file while load() runs."],"exampleFix":"# before\nann = Ann(log_level=3, tuning_level=1)\nnet_id = ann.load('/models/model.armnn', cached_network_path='/cache/model.ann')\n# ValueError: Cannot load model!  (stale /cache/model.ann from old libann)\n\n# after\nfrom pathlib import Path\nPath('/cache/model.ann').unlink(missing_ok=True)\nann = Ann(log_level=0)  # trace to see the parser error\nnet_id = ann.load('/models/model.armnn')","handlingStrategy":"try-catch","validationCode":"import hashlib\nfrom pathlib import Path\n\ndef validate_model_integrity(model_path: str, expected_sha256: str | None = None) -> None:\n    p = Path(model_path)\n    if not p.is_file() or p.stat().st_size == 0:\n        raise ValueError(f\"{model_path} missing or empty; cannot load\")\n    if expected_sha256:\n        h = hashlib.sha256()\n        h.update(p.read_bytes())\n        if h.hexdigest() != expected_sha256:\n            raise ValueError(f\"{model_path} hash mismatch; re-download\")\n\n# call before Ann.load():\nvalidate_model_integrity(model_path, expected_sha256=EXPECTED_HASH)","typeGuard":"from pathlib import Path\n\ndef looks_like_complete_model(model_path: str, min_size: int = 1024) -> bool:\n    p = Path(model_path)\n    return p.is_file() and p.stat().st_size > min_size","tryCatchPattern":"try:\n    net_id = ann.load(model_path, cached_network_path=cache)\nexcept ValueError as e:\n    if 'Cannot load model' in str(e):\n        log.error(\"libann rejected %s; removing stale cache and re-downloading\", model_path)\n        Path(model_path).unlink(missing_ok=True)\n        if cache:\n            Path(cache).unlink(missing_ok=True)\n        redownload(model_path)\n        net_id = ann.load(model_path)  # single retry without stale cache\n    else:\n        raise","preventionTips":["Treat cached_network_path as disposable: delete it whenever libann or the model version changes.","Verify file hashes/sizes after download to catch truncation before load().","Re-export models using ops supported by the bundled Arm NN version, and pin that version in CI."],"tags":["armnn","native-library","model-loading","corruption"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}