babalae/better-genshin-impact · warning · FormatException
曲谱缺少 notes 字段
Error message
曲谱缺少 notes 字段
What it means
Thrown by MusicScoreParser.ParseJsonAsync when the parsed JSON object does not contain a 'notes' property (json["notes"] is null). The 'notes' field is mandatory for all supported score types (yuanqin, midi, keyboard). Note: at the outer ParseAsync level, this FormatException is caught and converted into an invalid PerformanceScore with an Error field, so it does not crash the application.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:63
}
catch (Exception e)
{
return CreateInvalidScore(path, rootFolder, e.Message);
}
}
private static async Task<PerformanceScore> ParseJsonAsync(
string path,
string rootFolder,
CancellationToken cancellationToken)
{
var text = await File.ReadAllTextAsync(path, cancellationToken);
var json = JObject.Parse(text);
var type = GetString(json, "type", "yuanqin").Trim().ToLowerInvariant();
var bpm = GetDouble(json, "bpm", 120);
var ticks = Math.Max(1, (int)Math.Round(GetDouble(json, "ticks", 480)));
var timeSignature = GetString(json, "time_signature", "4/4");
var notes = json["notes"] ?? throw new FormatException("曲谱缺少 notes 字段");
var format = type switch
{
"yuanqin" => MusicScoreFormat.YuanQin,
"midi" => MusicScoreFormat.MidiJson,
"keyboard" => MusicScoreFormat.Keyboard,
_ => throw new FormatException($"不支持的 AutoYuanQin 曲谱类型:{type}")
};
var timeline = format switch
{
MusicScoreFormat.YuanQin => ParseYuanQinTimeline(notes, bpm, timeSignature),
MusicScoreFormat.MidiJson => ParseMidiJsonTimeline(GetNotesString(notes, format), bpm, ticks),
MusicScoreFormat.Keyboard => ParseKeyboardTimeline(GetNotesString(notes, format), bpm),
_ => PerformanceTimeline.Empty
};
return new PerformanceScoreView on GitHub (pinned to a7cb36712d)
Solutions
- Open the score JSON file and add a 'notes' field (string for yuanqin/keyboard, array for yuanqin object form, or string for midi format).
- Validate the JSON schema before parsing — check for 'notes' presence with a JSON schema validator.
- Refer to existing valid score files in the project for the correct schema.
- Check the PerformanceScore.Error property after ParseAsync to surface the message to the user gracefully.
Example fix
// before
var notes = json["notes"] ?? throw new FormatException("曲谱缺少 notes 字段");
// after — include the file path for diagnosis
var notes = json["notes"] ?? throw new FormatException(
$"曲谱缺少 notes 字段,文件:{Path.GetFileName(path)}"); Defensive patterns
Strategy: validation
Validate before calling
var json = JObject.Parse(text);
if (json["notes"] == null)
{
logger.LogError("曲谱缺少 notes 字段");
return; // or return invalid score
} Type guard
static bool HasNotesField(JObject json) => json["notes"] != null;
Try / catch
var score = await parser.ParseAsync(path, rootFolder, ct);
if (!string.IsNullOrEmpty(score.Error)) { logger.LogWarning("曲谱解析失败:{Error}", score.Error); } Prevention
- Validate score JSON files have a 'notes' field before loading.
- Check PerformanceScore.Error after ParseAsync instead of catching exceptions.
- Provide a template/example score file for users.
When it happens
Trigger: Loading a .json score file that has valid JSON but lacks the top-level 'notes' key. The JObject.Parse succeeds, but json["notes"] returns null.
Common situations: A user-edited or auto-generated score file omits the notes field; the file uses a different schema; a template/stub file was saved without content.
Related errors
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/e06a2ff2d9c65643.
Report an issue: GitHub.