{"record":{"id":"5760e93db4d60688","repo":"babalae/better-genshin-impact","slug":"closing-value","errorCode":null,"errorMessage":"键谱缺少右括号：{closing.Value}","messagePattern":"键谱缺少右括号：(.+?)","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs","lineNumber":538,"sourceCode":"            }\n            else\n            {\n                node = new KeyboardNode('\\0', current, []);\n                index++;\n            }\n\n            while (index < text.Length && text[index] == '-')\n            {\n                node.Multiplier++;\n                index++;\n            }\n\n            nodes.Add(node);\n        }\n\n        if (closing.HasValue)\n        {\n            throw new FormatException($\"键谱缺少右括号：{closing.Value}\");\n        }\n\n        return nodes;\n    }\n\n    private static void UnfoldKeyboardNode(\n        KeyboardNode node,\n        double startBeat,\n        double durationBeat,\n        ICollection<KeyboardNote> output)\n    {\n        if (node.Value.HasValue)\n        {\n            var key = char.ToUpperInvariant(node.Value.Value);\n            if (key != '0' && SupportedKeys.Contains(key))\n            {\n                output.Add(new KeyboardNote(key, startBeat, 0, durationBeat));\n            }","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs#L520-L556","documentation":"A FormatException from ParseKeyboardNodes thrown at end-of-text when a closing parameter was expected (closing.HasValue) but never matched. Each recursive call expects its specific closer; reaching the end of the string without it means an opening bracket was never closed.","triggerScenarios":"A keyboard-score string with an unclosed bracket, e.g. '(QW', '[AB', or '{CD'. The message echoes the expected closing character.","commonSituations":"Truncated score; manual editing that deleted a closing bracket; a group nested incorrectly so the closer landed at the wrong scope.","solutions":["Add the missing closing bracket indicated by {closing.Value} (e.g. append ')' for an unclosed '(').","Use a bracket-matching editor to verify the structure.","Route through ParseAsync to surface InvalidScore.Error.","Lint the score for bracket balance before parsing."],"exampleFix":"// before\n\"notes\":\"(QW-\"\n// after\n\"notes\":\"(QW-)\"","handlingStrategy":"validation","validationCode":"static bool AllBracketsClosed(string s)\n{\n    var st = new Stack<char>();\n    foreach (var c in s)\n    {\n        if (c is '(' or '[' or '{') st.Push(c);\n        else if (c is ')' or ']' or '}') { if (st.Count == 0) return false; st.Pop(); }\n    }\n    return st.Count == 0;\n}","typeGuard":"null","tryCatchPattern":"var score = await parser.ParseAsync(path, root, ct);\nif (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; }","preventionTips":["Balance every opening bracket with its matching closer.","Lint before parse to catch unclosed groups.","Use ParseAsync for InvalidScore reporting."],"tags":["music-score","keyboard-score","input-validation","parsing"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}