immich-app/immich · critical · FileNotFoundError
Recognition charset not found: {charset_path}
Error message
Recognition charset not found: {charset_path} What it means
`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.
Source
Thrown at machine-learning/immich_ml/models/ocr/ctc.py:25
def greedy(outputs: Sequence[NDArray[Any]]) -> tuple[NDArray[np.int32], NDArray[np.float32]]:
"""Models with an in-graph argmax head emit (indices, probs); the rest emit raw logits."""
if len(outputs) == 2:
return outputs[0], outputs[1]
(probs,) = outputs
indices = probs.argmax(axis=2)
return indices.astype(np.int32), np.take_along_axis(probs, indices[:, :, None], axis=2)[:, :, 0]
class CtcDecoder:
def __init__(self, charset: list[str]):
self.charset = ["", *charset, " "] # PP-OCR: blank at 0, space last
@classmethod
def from_file(cls, charset_path: Path) -> Self:
if not charset_path.is_file():
raise FileNotFoundError(f"Recognition charset not found: {charset_path}")
return cls(charset_path.read_text(encoding="utf-8").splitlines())
def __len__(self) -> int:
return len(self.charset)
def decode(self, indices: NDArray[np.int32], probs: NDArray[np.float32]) -> tuple[list[str], NDArray[np.float32]]:
keep = np.empty(indices.shape, dtype=bool)
keep[:, 0] = True
np.not_equal(indices[:, 1:], indices[:, :-1], out=keep[:, 1:]) # repeats before blanks
keep &= indices != 0
scores: NDArray[np.float32] = np.where(keep, probs, 0).sum(1)
scores /= np.maximum(keep.sum(1), 1) # an all-blank row sums to 0, so it stays 0
texts = ["".join(map(self.charset.__getitem__, row[k])) for row, k in zip(indices, keep)]
return texts, scores
View on GitHub (pinned to 5666d57f15)
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.
Example fix
# before docker run ... -v $HOME/models:/app/machines # shadows bundled assets # after cp en_dict.txt $HOME/models/ocr/ # or stop shadowing the assets dir # verify: ls /app/machines/ocr/en_dict.txt inside the container
Defensive patterns
Strategy: validation
Validate before calling
# check the charset file before loading the model
from pathlib import Path
cs = Path(model_dir) / 'en_dict.txt'
if not cs.is_file():
raise SystemExit(f'missing charset file: {cs} - reinstall ML assets or copy model dict') Type guard
def charset_file_ok(path) -> bool:
from pathlib import Path
p = Path(path)
return p.is_file() and p.stat().st_size > 0 Try / catch
try:
charset = CtcCharSet.from_file(charset_path)
except FileNotFoundError as e:
logger.error(str(e))
raise SystemExit('OCR charset missing; reinstall model assets or fix model_dir') Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unknown model combination: {source}, {model_type}, {model_ta
- Attempted to clear cache, but rmtree is not safe on this pla
- Unknown CLIP model: ${newConfig.machineLearning.clip.modelNa
- Unknown CLIP model: ${modelName}
- The ${name} extension is not available in this Postgres inst
AI-assisted analysis of immich-app/immich@5666d57f15 (2026-09-01).
Data as JSON: /api/errors/c37cbf2643cfa667.
Report an issue: GitHub.