{"record":{"id":"fa532c1ed252a8b9","repo":"babalae/better-genshin-impact","slug":"alias","errorCode":null,"errorMessage":"未找到模板别名 {alias}","messagePattern":"未找到模板别名 (.+?)","errorType":"exception","errorClass":"KeyNotFoundException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs","lineNumber":313,"sourceCode":"            return string.IsNullOrWhiteSpace(templateMode)\n                ? ImreadModes.Color\n                : ParseEnumExact<ImreadModes>(templateMode, nameof(templateMode));\n        }\n\n        private string ResolveTemplate(string? template, string objectName)\n        {\n            if (string.IsNullOrWhiteSpace(template))\n            {\n                throw new InvalidOperationException($\"对象 {objectName} 缺少 template 配置\");\n            }\n\n            var resolved = template.Trim();\n            while (resolved.StartsWith('@'))\n            {\n                var alias = resolved[1..];\n                if (!_config.Templates.TryGetValue(alias, out resolved))\n                {\n                    throw new KeyNotFoundException($\"未找到模板别名 {alias}\");\n                }\n            }\n\n            return resolved;\n        }\n\n        private Rect EvaluateRect(string expression)\n        {\n            var resolved = ResolveRegionExpression(expression);\n            var value = EvaluateValue(resolved);\n            return value switch\n            {\n                Rect rect => rect,\n                _ => throw new InvalidOperationException($\"表达式 {expression} 未返回 Rect\")\n            };\n        }\n\n        private string ResolveRegionExpression(string expression)","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs#L295-L331","documentation":"A template value may start with '@' to reference a named alias defined in the JSON templates map. ResolveTemplate dereferences the alias and throws KeyNotFoundException when the alias is not declared, so the template chain cannot resolve to a real file.","triggerScenarios":"An object has \"template\": \"@sharedBtn\" but the Recognition.json defines no templates.sharedBtn entry.","commonSituations":"Alias renamed or deleted but still referenced; typo in the alias name; alias defined in a different file that was not merged.","solutions":["Declare the alias in the templates map, e.g. \"templates\": { \"sharedBtn\": \"btn.png\" }.","Replace the @alias reference with a direct filename if the alias is not needed.","Check alias spelling and case against the templates map keys."],"exampleFix":"// before\n// \"template\": \"@sharedBtn\"  with no templates.sharedBtn -> throws\n\n// after\n// \"templates\": { \"sharedBtn\": \"btn_start.png\" },\n// \"objects\": { \"x\": { \"type\": \"TemplateMatch\", \"template\": \"@sharedBtn\" } }","handlingStrategy":"validation","validationCode":"foreach (var (name, cfg) in config.Objects)\n{\n    if (cfg.Template is { } t && t.TrimStart().StartsWith('@'))\n    {\n        var alias = t.Trim()[1..];\n        if (!config.Templates.ContainsKey(alias))\n            throw new InvalidOperationException($\"Object '{name}' references undefined template alias '@{alias}'.\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }\ncatch (KeyNotFoundException ex) when (ex.Message.Contains(\"未找到模板别名\"))\n{ Logger.LogError(ex, \"Undefined template alias referenced.\"); throw; }","preventionTips":["Keep templates map and @alias references in sync via a linter.","Prefer direct filenames when an alias is used only once.","Add a build-time check that every '@' template/region reference resolves."],"tags":["config","template","alias","key-not-found"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}