{"record":{"id":"c37cbf2643cfa667","repo":"immich-app/immich","slug":"recognition-charset-not-found-charset-path","errorCode":null,"errorMessage":"Recognition charset not found: {charset_path}","messagePattern":"Recognition charset not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"critical","filePath":"machine-learning/immich_ml/models/ocr/ctc.py","lineNumber":25,"sourceCode":"\n\ndef greedy(outputs: Sequence[NDArray[Any]]) -> tuple[NDArray[np.int32], NDArray[np.float32]]:\n    \"\"\"Models with an in-graph argmax head emit (indices, probs); the rest emit raw logits.\"\"\"\n    if len(outputs) == 2:\n        return outputs[0], outputs[1]\n    (probs,) = outputs\n    indices = probs.argmax(axis=2)\n    return indices.astype(np.int32), np.take_along_axis(probs, indices[:, :, None], axis=2)[:, :, 0]\n\n\nclass CtcDecoder:\n    def __init__(self, charset: list[str]):\n        self.charset = [\"\", *charset, \" \"]  # PP-OCR: blank at 0, space last\n\n    @classmethod\n    def from_file(cls, charset_path: Path) -> Self:\n        if not charset_path.is_file():\n            raise FileNotFoundError(f\"Recognition charset not found: {charset_path}\")\n        return cls(charset_path.read_text(encoding=\"utf-8\").splitlines())\n\n    def __len__(self) -> int:\n        return len(self.charset)\n\n    def decode(self, indices: NDArray[np.int32], probs: NDArray[np.float32]) -> tuple[list[str], NDArray[np.float32]]:\n        keep = np.empty(indices.shape, dtype=bool)\n        keep[:, 0] = True\n        np.not_equal(indices[:, 1:], indices[:, :-1], out=keep[:, 1:])  # repeats before blanks\n        keep &= indices != 0\n\n        scores: NDArray[np.float32] = np.where(keep, probs, 0).sum(1)\n        scores /= np.maximum(keep.sum(1), 1)  # an all-blank row sums to 0, so it stays 0\n        texts = [\"\".join(map(self.charset.__getitem__, row[k])) for row, k in zip(indices, keep)]\n        return texts, scores\n","sourceCodeStart":7,"sourceCodeEnd":41,"githubUrl":"https://github.com/immich-app/immich/blob/5666d57f15a66bd5518119c5d9f4d2b62f3a86c1/machine-learning/immich_ml/models/ocr/ctc.py#L7-L41","documentation":"`CtcCharSet.from_file` loads the character list used to decode CTC outputs for the OCR model. If the charset file does not exist at the given path it raises FileNotFoundError('Recognition charset not found: {charset_path}'). The ML service cannot start the OCR model without this file, since decoding requires the index-to-character mapping.","triggerScenarios":"Starting the immich_ml service with the OCR model enabled while the charset asset (e.g. en_dict.txt / ppocr charset file) is missing from the installed package or the mounted volume; a custom model directory lacking the charset file; Docker image built without the asset; wrong charset_path configured for a custom/local model.","commonSituations":"Partially copied or pruned installation missing model assets; running from source without downloading model files; custom PaddleOCR model with its own dict file that wasn't placed next to the model; volume mounts shadowing the package's assets directory.","solutions":["Check the path in the error and ensure the charset file exists there (ls the path inside the ML container/host).","Reinstall/re-pull the immich ML image or package so bundled model assets are restored.","If using a custom model, copy its dictionary/charset file to the expected path (charset_path) and ensure it's readable.","Fix volume mounts so they don't hide the package assets directory.","Point the model config to the correct directory containing the charset file."],"exampleFix":"# before\ndocker run ... -v $HOME/models:/app/machines # shadows bundled assets\n# after\ncp en_dict.txt $HOME/models/ocr/  # or stop shadowing the assets dir\n# verify: ls /app/machines/ocr/en_dict.txt inside the container","handlingStrategy":"validation","validationCode":"# check the charset file before loading the model\nfrom pathlib import Path\ncs = Path(model_dir) / 'en_dict.txt'\nif not cs.is_file():\n    raise SystemExit(f'missing charset file: {cs} - reinstall ML assets or copy model dict')","typeGuard":"def charset_file_ok(path) -> bool:\n    from pathlib import Path\n    p = Path(path)\n    return p.is_file() and p.stat().st_size > 0","tryCatchPattern":"try:\n    charset = CtcCharSet.from_file(charset_path)\nexcept FileNotFoundError as e:\n    logger.error(str(e))\n    raise SystemExit('OCR charset missing; reinstall model assets or fix model_dir')","preventionTips":["Verify model directories contain all required assets (weights, config, charset/dict file) before starting the service.","Don't volume-mount over the package's assets directory without including the bundled files.","Use official/pinned ML images so bundled model assets are present.","For custom OCR models, ship the matching dictionary file next to the model and point charset_path at it.","Add a startup health check that validates all configured model files exist."],"tags":["python","file-not-found","ocr","machine-learning","config"],"backgroundTag":"model-file-missing","analyzedSha":"5666d57f15a66bd5518119c5d9f4d2b62f3a86c1","analyzedAt":"2026-09-01T05:20:49.208Z","contentChangedAt":"2026-09-01T05:20:49.208Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}