babalae/better-genshin-impact · error · FormatException
{format} 曲谱的 notes 必须是字符串
Error message
{format} 曲谱的 notes 必须是字符串 What it means
A FormatException from GetNotesString thrown when the "notes" token of a MIDI-JSON or keyboard-format score is not a JSON string. For these two formats the parser expects the entire notes payload to be a single delimited string (not an array/object); a different JTokenType is rejected.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:695
return token == null || token.Type == JTokenType.Null
? fallback
: token.ToString();
}
private static double GetDouble(JObject json, string propertyName, double fallback)
{
var value = GetString(json, propertyName, fallback.ToString(CultureInfo.InvariantCulture));
return double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)
&& result > 0
? result
: fallback;
}
private static string GetNotesString(JToken notes, MusicScoreFormat format)
{
return notes.Type == JTokenType.String
? notes.Value<string>() ?? string.Empty
: throw new FormatException($"{format} 曲谱的 notes 必须是字符串");
}
private static PerformanceScore CreateInvalidScore(string path, string rootFolder, string error)
{
return new PerformanceScore
{
FullPath = path,
RelativePath = Path.GetRelativePath(rootFolder, path),
Name = Path.GetFileNameWithoutExtension(path),
Format = Path.GetExtension(path).Equals(".json", StringComparison.OrdinalIgnoreCase)
? MusicScoreFormat.YuanQin
: MusicScoreFormat.MidiFile,
Error = error
};
}
[GeneratedRegex(@"^(?<status>[DU])(?<keys>[A-Z@]+)(?<ticks>\d+)$", RegexOptions.CultureInvariant)]
private static partial Regex MidiJsonEventRegex();View on GitHub (pinned to a7cb36712d)
Solutions
- Set the score "type" to match the notes shape: use "yuanqin" for an array, or "midi"/"keyboard" for a string.
- If the type is correct, convert the notes value to a single string in the format the parser expects.
- Route through ParseAsync to surface InvalidScore.Error with the format name.
- Add a type-vs-notes-shape validator before parsing.
Example fix
// before (midi type but array notes)
{"type":"midi","notes":["DQ:0"]}
// after
{"type":"midi","notes":"DQ:0|UQ:480"} Defensive patterns
Strategy: validation
Validate before calling
static bool NotesShapeMatchesType(string type, JToken notes)
=> type switch
{
"yuanqin" => notes is JArray,
"midi" or "keyboard" => notes.Type == JTokenType.String,
_ => false
}; Type guard
static bool IsNotesString(JToken t) => t.Type == JTokenType.String;
Try / catch
var score = await parser.ParseAsync(path, root, ct);
if (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; } Prevention
- Match the "type" field to the notes shape (array for yuanqin, string for midi/keyboard).
- Validate type-vs-notes shape before parsing.
- Use ParseAsync for InvalidScore reporting.
When it happens
Trigger: A JSON score with type "midi" or "keyboard" whose "notes" is an array or object (e.g. notes:[...] or notes:{...}) instead of a string. Yuanqin does not hit this path because it uses ParseYuanQinTimeline which expects a JArray.
Common situations: Using a yuanqin-style notes array with type set to "midi"; exporter that emits notes as an array for a format that expects a string; copy-paste of a notes array into a midi/keyboard score.
Related errors
- yuanqin 音符对象缺少 note 字段
- 无法解析音符 {keys} 的时值
- 无法解析 MIDI JSON 变速标记:{rawPart}
- 无法解析 MIDI JSON 事件:{rawPart}
- 键谱出现不匹配的括号:{current}
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/3e923f9aad5c3a7f.
Report an issue: GitHub.