{"record":{"id":"bb0e075d197e92b5","repo":"k1tbyte/Wand-Enhancer","slug":"patchname-failed-to-resolve-groupname","errorCode":null,"errorMessage":"{patchName} failed to resolve {groupName}","messagePattern":"(.+?) failed to resolve (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"WandEnhancer/Core/EnhancerConfig.cs","lineNumber":34,"sourceCode":"        public class PatchEntry\n        {\n            public Regex Target { get; set; }\n            public string Patch { get; set; }\n            public Func<Match, string> PatchFactory { get; set; }\n            public string Name { get; set; }\n            public bool Applied { get; set; }\n            public bool SingleMatch { get; set; } = true;\n            public string[] CandidateFileNames { get; set; }\n            public string[] SearchHints { get; set; }\n            public ResolveContext Resolver { get; set; }\n        }\n\n        private static string RequireGroup(Match match, string groupName, string patchName)\n        {\n            var group = match.Groups[groupName];\n            if (!group.Success || string.IsNullOrEmpty(group.Value))\n            {\n                throw new Exception($\"{patchName} failed to resolve {groupName}\");\n            }\n\n            return group.Value;\n        }\n\n        private static string RequirePattern(string source, string pattern, string groupName, string patchName)\n        {\n            var match = Regex.Match(source, pattern, RegexOptions.Singleline);\n            return RequireGroup(match, groupName, patchName);\n        }\n\n        private static string BuildSetAccountLanguagePatch(Match match)\n        {\n            var parameters = RequireGroup(match, \"params\", \"setAccountLanguage\");\n            var expr = RequireGroup(match, \"expr\", \"setAccountLanguage\");\n            return $\"setAccountLanguage({parameters}){{return ({expr}).then(response=>{{response&&\\\"object\\\"==typeof response&&(response.subscription={{period:\\\"yearly\\\",state:\\\"active\\\"}});return response;}})}}\";\n        }\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/k1tbyte/Wand-Enhancer/blob/643c8f8b62cbb26fd3ac105b92497d9a9c445f08/WandEnhancer/Core/EnhancerConfig.cs#L16-L52","documentation":"RequireGroup checks a named capture group on a Match; if the group did not participate (!group.Success) or captured empty, it throws. RequireGroup is used by every PatchFactory builder in EnhancerConfig (BuildSetAccountLanguagePatch, BuildSetAccountReducerPatch, BuildRemoteBridgeResetPatch, BuildRemoteBridgeSyncSnapshotPatch). The message names patchName and groupName so the drifted sub-pattern is identifiable.","triggerScenarios":"A PatchFactory runs after the outer Target matched; it calls RequireGroup(match, groupName, patchName) or RequirePattern(source, pattern, groupName, patchName), and the named group (params, expr, decl, fn, state, account, method, disposable, instance, trainerId, versions, trainer, game, installation, remote, values, theme, settings, language, timer, etc.) did not capture.","commonSituations":"The minifier renamed/reshaped an identifier the factory assumed (function param list changed, private-field naming changed, statement order changed); the outer Target regex still matched but a sub-pattern inside RequirePattern no longer fits the new body.","solutions":["From the message's patchName + groupName, locate the RequireGroup/RequirePattern call in EnhancerConfig (e.g. EnhancerConfig.cs:48-49 for setAccountLanguage).","Extract the matched region from the live app-*.bundle.js (the outer Target regex still matches it).","Update the named-group pattern (or loosen the outer Target) to capture the new shape.","Re-derive against the actual shipped bundle — AGENTS.md warns NOT to trust .source/new, it is a different version.","Re-run patch."],"exampleFix":"// before (param list shape changed in new build)\nprivate static string BuildSetAccountLanguagePatch(Match match) {\n    var parameters = RequireGroup(match, \"params\", \"setAccountLanguage\");\n    ...\n}\n// Target regex with tighter params group that still captures after refactor\nTarget = new Regex(\n    @\"setAccountLanguage\\((?<params>[^)]*)\\)\\{\\s*return\\s+(?<expr>this\\.\\#\\w+\\.post\\(\"\"/v3/account/language\"\",\\{[^}]*\\}\\))\\s*;?\\s*\\}\",\n    RegexOptions.Singleline);","handlingStrategy":"try-catch","validationCode":"// Optional: dry-run PatchFactory builders on the live bundle to catch drift early\nforeach (var (type, entries) in EnhancerConfig.GetInstance()) {\n    if (!_config.PatchTypes.Contains(type)) continue;\n    foreach (var p in entries.Where(e => e.PatchFactory != null)) {\n        var m = p.Target.Match(bundle);\n        if (m.Success) try { p.PatchFactory(m); } catch (Exception ex) { _logger($\"WARN {p.Name}: \" + ex.Message, ELogType.Warning); }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    enhancer.Patch();\n} catch (Exception ex) when (ex.Message.Contains(\"failed to resolve\")) {\n    // named group drifted; re-derive against the live bundle (not .source/new)\n}","preventionTips":["Always re-derive regexes against the shipped bundle, never against .source/new.","Add a CI test that runs every PatchFactory against the latest bundle.","Use stable anchors (URLs, action strings) for named-group boundaries."],"tags":["regex","version-drift","patch-factory","named-group"],"backgroundTag":null,"analyzedSha":"643c8f8b62cbb26fd3ac105b92497d9a9c445f08","analyzedAt":"2026-08-13T14:17:43.823Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}