babalae/better-genshin-impact · error · KeyNotFoundException

未找到变量 {name}

Error message

未找到变量 {name}

What it means

ResolveVariable throws KeyNotFoundException when a variable name is not present in the config.Vars map. Under normal flow BuildParameters only iterates declared vars, so this is a defensive guard against a variable referenced through the expression machinery that is not declared in the vars map.

Source

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

                    continue;
                }

                parameters[varName] = ResolveVariable(varName);
            }

            return parameters;
        }

        private double ResolveVariable(string name)
        {
            if (_resolvedVars.TryGetValue(name, out var resolvedValue))
            {
                return resolvedValue;
            }

            if (!_config.Vars.TryGetValue(name, out var expression))
            {
                throw new KeyNotFoundException($"未找到变量 {name}");
            }

            if (!_resolvingVars.Add(name))
            {
                throw new InvalidOperationException($"变量 {name} 存在循环引用");
            }

            try
            {
                var value = ToDouble(EvaluateValue(expression, name));
                _resolvedVars[name] = value;
                return value;
            }
            finally
            {
                _resolvingVars.Remove(name);
            }
        }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Declare the missing variable in the vars map.
  2. Remove the dangling reference from the referencing var's expression.
  3. Use a builtin (cw, ch, cx, cy, s) instead of an undeclared name.

Example fix

// before
// "vars": { "a": "b + 1" }   // b is not declared -> ResolveVariable('b') throws

// after
// "vars": { "a": "b + 1", "b": "10" }
Defensive patterns

Strategy: validation

Validate before calling

var builtins = new HashSet<string>(StringComparer.Ordinal) { "cw", "ch", "cx", "cy", "s" };
foreach (var (name, expr) in config.Vars)
{
    // crude token check: any identifier not a builtin/function/number must be in vars
    foreach (var token in System.Text.RegularExpressions.Regex.Matches(expr, "[A-Za-z_][A-Za-z0-9_]*"))
    {
        var id = token.ToString()!;
        if (!builtins.Contains(id) && !config.Vars.ContainsKey(id)
            && !new[]{"rect","cutLeft","cutRight","cutTop","cutBottom","cutLeftTop","cutRightTop","cutLeftBottom","cutRightBottom"}.Contains(id))
            throw new InvalidOperationException($"Var '{name}' references undeclared variable '{id}'.");
    }
}

Try / catch

try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }
catch (KeyNotFoundException ex) when (ex.Message.Contains("未找到变量"))
{ Logger.LogError(ex, "Undeclared variable referenced by a var expression."); throw; }

Prevention

When it happens

Trigger: A var's expression references a name that survives NormalizeExpression but is absent from vars and from the builtins (cw/ch/cx/cy/s), e.g. after renaming a var and leaving a dangling reference inside another var's expression.

Common situations: Renamed a var in vars but forgot to update a var expression that referenced it; merged configs where a referenced var was removed.

Related errors


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