babalae/better-genshin-impact · critical · FileNotFoundException

PaddleOCR config file {modelConfigFileName} not found: {conf

Error message

PaddleOCR config file {modelConfigFileName} not found: {configFilePath}

What it means

PaddleOcrService loads the OCR character alphabet from inference.yml, which must sit next to the recognition ONNX model (path derived from BgiOnnxModel.ModalPath). This FileNotFoundException fires when that YAML config is missing, so the recognizer has no character dictionary and the service cannot initialize. It is raised inside DefaultRecLabelFunc, which every built-in model type (V4/V5/V6/latin/eslav/korean) uses unless a custom recLabel is supplied.

Source

Thrown at BetterGenshinImpact/Core/Recognition/OCR/Paddle/PaddleOcrService.cs:55

        String PreHeatImagePath
    )
    {
        public static string TestImagePath = Global.Absolute(@"Assets\Model\PaddleOCR\test_pp_ocr.png");

        public static string TestNumberImagePath =
            Global.Absolute(@"Assets\Model\PaddleOCR\test_pp_ocr_number.png");

        private static readonly Func<BgiOnnxModel, IReadOnlyList<string>> DefaultRecLabelFunc =
            recModel =>
            {
                const string modelConfigFileName = "inference.yml";
                var configFilePath = Path.Combine(
                    Path.GetDirectoryName(recModel.ModalPath) ??
                    throw new InvalidOperationException("Cannot get model directory"),
                    modelConfigFileName);

                if (!File.Exists(configFilePath))
                    throw new FileNotFoundException(
                        $"PaddleOCR config file {modelConfigFileName} not found: {configFilePath}");

                using var reader = new StreamReader(configFilePath);
                var parser = new Parser(reader);

                // Traverse YAML to find PostProcess:character_dict
                while (parser.MoveNext())
                {
                    if (parser.Current is not YamlDotNet.Core.Events.Scalar { Value: "PostProcess" }) continue;
                    parser.MoveNext(); // Should be MappingStart
                    while (parser.MoveNext())
                    {
                        if (parser.Current is not YamlDotNet.Core.Events.Scalar { Value: "character_dict" }) continue;
                        parser.MoveNext(); // Should be SequenceStart
                        var result = new List<string>();
                        while (parser.MoveNext())
                        {
                            switch (parser.Current)

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Restore inference.yml into the recognition model folder, e.g. Assets\Model\PaddleOCR\Rec\V5\PP-OCRv5_mobile_rec_infer\inference.yml.
  2. Confirm the ModelRelativePath registered in BgiOnnxModel (e.g. PaddleOcrRecV5) matches the on-disk folder where slim.onnx and inference.yml actually live.
  3. Check .gitignore / packaging rules are not excluding *.yml next to *.onnx.
  4. If the YAML is unavailable, build the model type via Create(...) with an explicit recLabel that returns the character list from another source.

Example fix

// before: model folder ships slim.onnx only -> DefaultRecLabelFunc throws
new PaddleOcrService(factory, PaddleOcrModelType.V5);

// after: validate the sidecar config before constructing
var rec = PaddleOcrModelType.V5.RecognitionModel;
var yml = Path.Combine(Path.GetDirectoryName(rec.ModalPath)!, "inference.yml");
if (!File.Exists(yml)) throw new InvalidOperationException($"Missing OCR config {yml}; restore the model package.");
new PaddleOcrService(factory, PaddleOcrModelType.V5);
Defensive patterns

Strategy: validation

Validate before calling

bool IsPaddleConfigReady(BgiOnnxModel recModel)
{
    var dir = Path.GetDirectoryName(recModel.ModalPath);
    if (dir is null) return false;
    return File.Exists(Path.Combine(dir, "inference.yml"));
}

// before constructing the service:
if (!IsPaddleConfigReady(PaddleOcrModelType.V5.RecognitionModel))
    throw new InvalidOperationException("PaddleOCR inference.yml missing next to the recognition model.");

Try / catch

try
{
    _ocr = new PaddleOcrService(factory, PaddleOcrModelType.V5);
}
catch (FileNotFoundException ex) when (ex.FileName?.EndsWith("inference.yml", StringComparison.OrdinalIgnoreCase) == true
    || ex.Message.Contains("inference.yml", StringComparison.OrdinalIgnoreCase))
{
    Logger.LogError(ex, "PaddleOCR config missing; OCR disabled.");
    _ocr = null; // or fall back to an alternate IOcrService
}

Prevention

When it happens

Trigger: Constructing PaddleOcrService with a PaddleOcrModelType whose recognition model directory contains slim.onnx but not inference.yml. Happens during the Build() call that wires up the Rec model, i.e. inside the PaddleOcrService constructor.

Common situations: Model package repackaged without the .yml; .gitignore or packaging step filtering out .yml files; partial Git checkout; model folder moved so ModalPath no longer points at the real directory; case-sensitivity mismatch on the file name.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/b4bf3547b063017c. Report an issue: GitHub.