babalae/better-genshin-impact · error · KeyNotFoundException

未找到区域别名 {alias}

Error message

未找到区域别名 {alias}

What it means

A region (ROI) expression may start with '@' to reference a named alias from the JSON regions map. ResolveRegionExpression dereferences it and throws KeyNotFoundException when the alias is undefined, so the rectangle cannot be resolved.

Source

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

        {
            var resolved = ResolveRegionExpression(expression);
            var value = EvaluateValue(resolved);
            return value switch
            {
                Rect rect => rect,
                _ => throw new InvalidOperationException($"表达式 {expression} 未返回 Rect")
            };
        }

        private string ResolveRegionExpression(string expression)
        {
            var resolved = expression.Trim();
            while (resolved.StartsWith('@'))
            {
                var alias = resolved[1..];
                if (!_config.Regions.TryGetValue(alias, out resolved))
                {
                    throw new KeyNotFoundException($"未找到区域别名 {alias}");
                }
            }

            return resolved;
        }

        private object EvaluateValue(string expression, string? skipVarName = null)
        {
            var normalizedExpression = NormalizeExpression(expression);
            var ncalcExpression = new Expression(normalizedExpression);

            foreach (var (name, value) in BuildParameters(skipVarName))
            {
                ncalcExpression.Parameters[name] = value;
            }

            ncalcExpression.Functions["rect"] = args => BuildRect(args.Evaluate(0), args.Evaluate(1), args.Evaluate(2), args.Evaluate(3));
            ncalcExpression.Functions["cutLeft"] = args => _captureRect.CutLeft(ToDouble(args.Evaluate(0)));

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Declare the region alias in the regions map, e.g. "regions": { "topBar": "rect(0,0,cw,40)" }.
  2. Inline the rect expression directly in roi if the alias is not needed.
  3. Check alias spelling and case against the regions map keys.

Example fix

// before
// "roi": "@topBar"  with no regions.topBar -> throws

// after
// "regions": { "topBar": "rect(0, 0, cw, 40)" },
// "objects": { "x": { "roi": "@topBar" } }
Defensive patterns

Strategy: validation

Validate before calling

foreach (var (name, cfg) in config.Objects)
{
    if (cfg.Roi is { } r && r.TrimStart().StartsWith('@'))
    {
        var alias = r.Trim()[1..];
        if (!config.Regions.ContainsKey(alias))
            throw new InvalidOperationException($"Object '{name}' references undefined region alias '@{alias}'.");
    }
}

Try / catch

try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }
catch (KeyNotFoundException ex) when (ex.Message.Contains("未找到区域别名"))
{ Logger.LogError(ex, "Undefined region alias referenced."); throw; }

Prevention

When it happens

Trigger: An object has "roi": "@topBar" but the Recognition.json defines no regions.topBar entry.

Common situations: Region alias removed/renamed but still referenced; typo in the alias; alias defined in a shared file not loaded.

Related errors


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