babalae/better-genshin-impact · error · FormatException
yuanqin 音符对象缺少 note 字段
Error message
yuanqin 音符对象缺少 note 字段
What it means
A FormatException raised inside ParseYuanQinTokens while iterating the "notes" array of a yuanqin-format AutoYuanQin JSON score. Each element must be an object carrying a non-empty "note" field (the key letters). GetString returns an empty fallback when the field is absent or null, and IsNullOrWhiteSpace then trips this throw. It is a contract violation in the score file, not a transient runtime fault.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:351
}
return tokens;
}
private static List<YuanQinToken> ParseYuanQinTokens(JArray notes)
{
var tokens = new List<YuanQinToken>(notes.Count);
foreach (var item in notes)
{
if (item is not JObject note)
{
throw new FormatException("yuanqin 音符数组中包含非对象元素");
}
var keys = GetString(note, "note", string.Empty);
if (string.IsNullOrWhiteSpace(keys))
{
throw new FormatException("yuanqin 音符对象缺少 note 字段");
}
var special = GetString(note, "spl", "none");
if (special is "^" or "&")
{
tokens.Add(new YuanQinToken(keys, 0, special));
continue;
}
if (!double.TryParse(
note["type"]?.ToString(),
NumberStyles.Float,
CultureInfo.InvariantCulture,
out var denominator))
{
throw new FormatException($"无法解析音符 {keys} 的时值");
}
View on GitHub (pinned to a7cb36712d)
Solutions
- Open the offending .json file and confirm every object in the notes array has a non-empty "note" field (e.g. {"note":"Q","type":4}).
- If you generated the file with a converter, regenerate it and verify the converter emits the "note" key, not a synonym.
- At the public API surface (ParseAsync) this throw is already swallowed and converted into a PerformanceScore with Error set, so surface score.Error to the user instead of letting the raw exception propagate.
- Add a JSON-schema pre-check on yuanqin files before parsing so malformed notes are reported with the offending index.
Example fix
// before: note object missing the field
{"type":"yuanqin","bpm":120,"notes":[{"type":4}]}
// after: every note carries "note"
{"type":"yuanqin","bpm":120,"notes":[{"note":"Q","type":4}]} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate a yuanqin notes array before parsing
static bool HasValidYuanQinNotes(JToken notes)
{
if (notes is not JArray arr) return false;
foreach (var item in arr)
{
if (item is not JObject o) return false;
var n = o["note"]?.ToString();
if (string.IsNullOrWhiteSpace(n)) return false;
}
return true;
} Type guard
static bool IsYuanQinNoteObject(JToken t) => t is JObject o && !string.IsNullOrWhiteSpace(o["note"]?.ToString());
Try / catch
// ParseAsync already converts this to an InvalidScore; check the result
var score = await parser.ParseAsync(path, root, ct);
if (!string.IsNullOrEmpty(score.Error))
{
Log.Warning("跳过无效曲谱 {Path}: {Error}", path, score.Error);
continue;
} Prevention
- Always go through the public ParseAsync; it swallows parse exceptions into score.Error.
- Lint score files with a JSON schema before importing.
- Report the failing note index in your own validator for faster fixes.
When it happens
Trigger: Parsing a JSON score whose top-level "type" resolves to "yuanqin" where the "notes" JArray contains an element that is a JObject but has no "note" key, or whose "note" value is an empty/whitespace string.
Common situations: Hand-edited or converter-generated yuanqin files where a note object was dropped to {}; scores exported by a tool that renamed the key (e.g. "key"/"k" instead of "note"); a truncated/copy-paste file missing fields.
Related errors
- 无法解析音符 {keys} 的时值
- 无法解析 MIDI JSON 变速标记:{rawPart}
- 无法解析 MIDI JSON 事件:{rawPart}
- {format} 曲谱的 notes 必须是字符串
- 键谱出现不匹配的括号:{current}
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/3c3abf3ec92e7169.
Report an issue: GitHub.