babalae/better-genshin-impact · warning · FormatException

yuanqin 曲谱的 notes 必须是字符串或音符对象数组

Error message

yuanqin 曲谱的 notes 必须是字符串或音符对象数组

What it means

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.

Source

Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:179

            Format = MusicScoreFormat.MidiFile,
            MidiNotes = notes,
            Tracks = tracks
        };
    }

    private static PerformanceTimeline ParseYuanQinTimeline(
        JToken sheet,
        double initialBpm,
        string timeSignature)
    {
        var tokens = sheet.Type switch
        {
            JTokenType.String => ParseYuanQinTokens(
                (sheet.Value<string>() ?? string.Empty)
                .Replace("\r", string.Empty)
                .Replace("\n", string.Empty)),
            JTokenType.Array => ParseYuanQinTokens((JArray)sheet),
            _ => throw new FormatException("yuanqin 曲谱的 notes 必须是字符串或音符对象数组")
        };
        var events = new List<PerformanceEvent>();
        var cursor = TimeSpan.Zero;
        var bpm = initialBpm;
        var beatDenominator = ParseBeatDenominator(timeSignature);

        for (var i = 0; i < tokens.Count; i++)
        {
            var token = tokens[i];
            if (token.Special == "%")
            {
                bpm = token.Denominator > 0 ? token.Denominator : bpm;
                continue;
            }

            if (token.Special is "^" or "&")
            {
                AddExplicitEvents(events, cursor, token.Keys, token.Special == "^");

View on GitHub (pinned to a7cb36712d)

Solutions

  1. 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.
  2. Verify against the yuanqin format documentation or example score files.
  3. Check the PerformanceScore.Error property for the exact message.
Defensive patterns

Strategy: validation

Validate before calling

var notesToken = json["notes"];
if (notesToken!.Type != JTokenType.String && notesToken.Type != JTokenType.Array)
{
    logger.LogError("notes 必须是字符串或数组");
    return;
}

Type guard

static bool IsValidYuanQinNotes(JToken token) => token.Type is JTokenType.String or JTokenType.Array;

Try / catch

var score = await parser.ParseAsync(path, rootFolder, ct);
if (!string.IsNullOrEmpty(score.Error)) { logger.LogWarning(score.Error); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/0fb04a1e8cf31740. Report an issue: GitHub.