{"record":{"id":"0fb04a1e8cf31740","repo":"babalae/better-genshin-impact","slug":"yuanqin-notes","errorCode":null,"errorMessage":"yuanqin 曲谱的 notes 必须是字符串或音符对象数组","messagePattern":"yuanqin 曲谱的 notes 必须是字符串或音符对象数组","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"warning","filePath":"BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs","lineNumber":179,"sourceCode":"            Format = MusicScoreFormat.MidiFile,\n            MidiNotes = notes,\n            Tracks = tracks\n        };\n    }\n\n    private static PerformanceTimeline ParseYuanQinTimeline(\n        JToken sheet,\n        double initialBpm,\n        string timeSignature)\n    {\n        var tokens = sheet.Type switch\n        {\n            JTokenType.String => ParseYuanQinTokens(\n                (sheet.Value<string>() ?? string.Empty)\n                .Replace(\"\\r\", string.Empty)\n                .Replace(\"\\n\", string.Empty)),\n            JTokenType.Array => ParseYuanQinTokens((JArray)sheet),\n            _ => throw new FormatException(\"yuanqin 曲谱的 notes 必须是字符串或音符对象数组\")\n        };\n        var events = new List<PerformanceEvent>();\n        var cursor = TimeSpan.Zero;\n        var bpm = initialBpm;\n        var beatDenominator = ParseBeatDenominator(timeSignature);\n\n        for (var i = 0; i < tokens.Count; i++)\n        {\n            var token = tokens[i];\n            if (token.Special == \"%\")\n            {\n                bpm = token.Denominator > 0 ? token.Denominator : bpm;\n                continue;\n            }\n\n            if (token.Special is \"^\" or \"&\")\n            {\n                AddExplicitEvents(events, cursor, token.Keys, token.Special == \"^\");","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs#L161-L197","documentation":"Thrown by MusicScoreParser.ParseYuanQinTimeline when the 'notes' JToken is neither a JSON string (JTokenType.String) nor a JSON array (JTokenType.Array). For yuanqin format, notes must be either a string of sheet notation or an array of note objects. Any other JTokenType (object, number, boolean, null) triggers this FormatException.","triggerScenarios":"A yuanqin-type score where 'notes' is a JSON number, object, boolean, or null. For example, \"notes\": 123 or \"notes\": {\"key\": \"A\"} instead of a string or array.","commonSituations":"Manually editing a score file and putting the wrong JSON type for notes; a converter/exporter tool producing notes as a nested object instead of a string/array.","solutions":["Change the 'notes' value to a JSON string of yuanqin sheet notation (e.g. \"Q[1] W[2]\") or a JSON array of note objects.","Verify against the yuanqin format documentation or example score files.","Check the PerformanceScore.Error property for the exact message."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var notesToken = json[\"notes\"];\nif (notesToken!.Type != JTokenType.String && notesToken.Type != JTokenType.Array)\n{\n    logger.LogError(\"notes 必须是字符串或数组\");\n    return;\n}","typeGuard":"static bool IsValidYuanQinNotes(JToken token) => token.Type is JTokenType.String or JTokenType.Array;","tryCatchPattern":"var score = await parser.ParseAsync(path, rootFolder, ct);\nif (!string.IsNullOrEmpty(score.Error)) { logger.LogWarning(score.Error); }","preventionTips":["Ensure notes is a string or array in yuanqin scores.","Validate JSON token types before deep parsing.","Use example score files as schema reference."],"tags":["music","json","format-exception","yuanqin","user-content"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}