babalae/better-genshin-impact · error · InvalidOperationException

{fieldName} 不能为空

Error message

{fieldName} 不能为空

What it means

ParseEnumExact rejects null or whitespace for fields parsed as enums. The always-required type field goes through it unconditionally, and conditional fields (templateMatchMode, colorCode, ocrEngine, anchor, templateMode) pass through it when present. InvalidOperationException signals the field must have a value.

Source

Thrown at BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs:498

        }

        private static Scalar BuildScalar(IReadOnlyList<double> values, string fieldName)
        {
            return values.Count switch
            {
                1 => new Scalar(values[0]),
                2 => new Scalar(values[0], values[1]),
                3 => new Scalar(values[0], values[1], values[2]),
                4 => new Scalar(values[0], values[1], values[2], values[3]),
                _ => throw new InvalidOperationException($"{fieldName} 必须是 1 到 4 个数字"),
            };
        }

        private static TEnum ParseEnumExact<TEnum>(string? value, string fieldName) where TEnum : struct, Enum
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new InvalidOperationException($"{fieldName} 不能为空");
            }

            if (Enum.TryParse<TEnum>(value, false, out var parsed))
            {
                return parsed;
            }

            throw new InvalidOperationException($"{fieldName} 的值 {value} 不是有效的 {typeof(TEnum).Name}");
        }

        private static Color ParseColor(string value)
        {
            return ColorTranslator.FromHtml(value);
        }

        private static double ToDouble(object? value)
        {
            return value switch

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Provide a valid enum value, e.g. "type": "TemplateMatch".
  2. Omit optional enum fields entirely rather than leaving them blank.
  3. Validate that required enum fields are non-empty before runtime.

Example fix

// before
// { }                       // no type -> throws
// { "type": "" }            // blank type -> throws

// after
// { "type": "TemplateMatch" }
Defensive patterns

Strategy: validation

Validate before calling

foreach (var (name, cfg) in config.Objects)
{
    if (string.IsNullOrWhiteSpace(cfg.Type))
        throw new InvalidOperationException($"Object '{name}' is missing required 'type'.");
}
// also ensure present optional enum fields are not blank:
foreach (var (name, cfg) in config.Objects)
{
    if (cfg.OcrEngine is "" or null && cfg.OcrEngine is not null)
        throw new InvalidOperationException($"Object '{name}' has blank ocrEngine; omit it instead.");
}

Try / catch

try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }
catch (InvalidOperationException ex) when (ex.Message.Contains("不能为空"))
{ Logger.LogError(ex, "A required enum field is blank."); throw; }

Prevention

When it happens

Trigger: A RecognitionObject omits type entirely or sets it to an empty string; or a present-but-blank enum field (e.g. "ocrEngine": "") reaches ParseEnumExact.

Common situations: Required type field removed; field left blank during editing; conditional enum field present as empty string instead of being omitted.

Related errors


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