{"record":{"id":"d8016b6db0b5cf47","repo":"babalae/better-genshin-impact","slug":"objectname-template","errorCode":null,"errorMessage":"对象 {objectName} 缺少 template 配置","messagePattern":"对象 (.+?) 缺少 template 配置","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs","lineNumber":304,"sourceCode":"            {\n                return Path.GetFileNameWithoutExtension(templateName);\n            }\n\n            return objectName;\n        }\n\n        private ImreadModes ParseTemplateMode(string? templateMode)\n        {\n            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);","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs#L286-L322","documentation":"For a TemplateMatch-type object the loader must resolve a template image. ResolveTemplate throws InvalidOperationException when the template field is null or whitespace, because there is no image to match against. This is a configuration error, not a runtime/state problem.","triggerScenarios":"A RecognitionObject whose type is TemplateMatch has no template field, or it is set to an empty string, in Recognition.json.","commonSituations":"Copied an object and forgot to add template; changed type from a color/text recognizer to TemplateMatch without adding the field; field commented out.","solutions":["Add \"template\": \"<filename or @alias>\" to the object in Recognition.json.","If no template is intended, change the object type away from TemplateMatch (e.g. to a color-range or OCR recognizer).","Validate the JSON with a schema check that requires template for TemplateMatch objects before runtime."],"exampleFix":"// before (Recognition.json)\n// { \"type\": \"TemplateMatch\" }  -> throws: missing template\n\n// after\n// { \"type\": \"TemplateMatch\", \"template\": \"btn_start.png\" }","handlingStrategy":"validation","validationCode":"// schema-level check before runtime\nforeach (var (name, cfg) in config.Objects)\n{\n    var t = cfg.Type?.Trim();\n    if (string.Equals(t, \"TemplateMatch\", StringComparison.Ordinal)\n        && string.IsNullOrWhiteSpace(cfg.Template))\n        throw new InvalidOperationException($\"Object '{name}' is TemplateMatch but has no template.\");\n}","typeGuard":null,"tryCatchPattern":"try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"缺少 template 配置\"))\n{ Logger.LogError(ex, \"TemplateMatch object missing template field.\"); throw; }","preventionTips":["Treat 'template' as required for every TemplateMatch object in your authoring tool/schema.","Review JSON diffs that change an object's type to TemplateMatch.","Add a CI schema check that enforces template presence for TemplateMatch."],"tags":["config","validation","template","template-match"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}