babalae/better-genshin-impact · error · FormatException
无法解析音符 {keys} 的时值
Error message
无法解析音符 {keys} 的时值 What it means
A FormatException from ParseYuanQinTokens thrown when the "type" field of a yuanqin note object cannot be parsed as a floating-point number. The "type" value is the beat denominator (e.g. 4 = quarter note) used to compute duration; a missing, null, or non-numeric value leaves the note without a valid duration. The parse uses NumberStyles.Float with the invariant culture, so locale-specific decimals like commas are rejected.
Source
Thrown at BetterGenshinImpact/GameTask/Music/Service/MusicScoreParser.cs:367
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} 的时值");
}
tokens.Add(new YuanQinToken(keys, denominator, special));
}
return tokens;
}
private static PerformanceTimeline ParseMidiJsonTimeline(string sheet, double initialBpm, int ticks)
{
var events = new List<PerformanceEvent>();
var cursor = TimeSpan.Zero;
var bpm = initialBpm;
string previousStatus = string.Empty;
string previousKeys = string.Empty;
var previousWasEvent = false;
var rawParts = sheet.Split(
'|',View on GitHub (pinned to a7cb36712d)
Solutions
- Ensure each non-special yuanqin note has a numeric "type" (e.g. 1, 2, 4, 8, 0.5) written with a dot decimal separator.
- Regenerate the score from its source tool and re-export.
- Because ParseAsync catches this, the file becomes an InvalidScore; inspect score.Error to find which file failed.
- Add a per-note validator that reports the index of the offending note before parsing.
Example fix
// before
{"note":"Q","type":"quarter"}
// after
{"note":"Q","type":4} Defensive patterns
Strategy: try-catch
Validate before calling
static bool HasValidYuanQinTypes(JToken notes)
{
if (notes is not JArray arr) return false;
foreach (var item in arr)
{
if (item is not JObject o) continue;
var spl = o["spl"]?.ToString();
if (spl is "^" or "&") continue;
var t = o["type"]?.ToString();
if (!double.TryParse(t, NumberStyles.Float, CultureInfo.InvariantCulture, out var d) || d <= 0)
return false;
}
return true;
} Type guard
static bool IsValidNoteType(JObject o) => double.TryParse(o["type"]?.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out _);
Try / catch
var score = await parser.ParseAsync(path, root, ct);
if (!string.IsNullOrEmpty(score.Error)) { Log.Warning(score.Error); continue; } Prevention
- Use dot decimal separators in exported type values.
- Validate before import to report the bad note index.
- Rely on ParseAsync's InvalidScore conversion.
When it happens
Trigger: A yuanqin note object whose "type" field is absent (note["type"]?.ToString() yields null/empty), set to a non-numeric string ("quarter"), or uses a comma decimal separator under a non-invariant convention.
Common situations: Scores edited in a spreadsheet that reformatted the type column to text; converter bug that omitted type on non-special notes; note objects where "type" was mistakenly stored as the note name.
Related errors
- yuanqin 音符对象缺少 note 字段
- 无法解析 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/676f55c343384ff7.
Report an issue: GitHub.