Every recoverable issue the parser or writer encounters is reported as a
LrcDiagnostic carrying a stable
code (LRC00xx), severity, 1-based line/column location, and a human-readable
message. Codes are exposed as constants on
LrcDiagnosticIds so consumers
can switch on them without coupling to an enum that changes between versions.
In tolerant mode (the default), every code below is collected on
LrcParseResult.Diagnostics and the
parser keeps going. In strict mode, the first Error-severity diagnostic causes
LrcParseException to be thrown.
Codes
Structural
Code
Severity
Trigger
Recovery
LRC0001UnclosedTag
Error
A [ opens with no matching ] before line end.
Skip rest of line.
LRC0002InvalidTimestamp
Error
Digit-prefixed […] that fails timestamp parsing (e.g. [00:99.00] — seconds out of range).
Skip the bracketed group; rest of line continues.
LRC0003MalformedIdTag
Error
[key] with no : (e.g. [bad]junk).
Skip the bracketed group.
LRC0004UnknownIdTag
Info
[xx:value] where xx isn't one of the known keys.
Preserved verbatim in Metadata.RawTags.
LRC0005InvalidOffset
Warning
[offset:not-a-number].
Tag preserved in RawTags; typed Offset unchanged.
LRC0006InvalidLength
Warning
[length:invalid].
Tag preserved in RawTags; typed Length unchanged.
LRC0007InvalidEnhancedTimestamp
Error
<bad> inside an enhanced line (text isn't a valid timestamp).
Word skipped; following text is preserved as literal line text.
LRC0008UnclosedEnhancedTimestamp
Error
< with no matching > before line end.
Skip rest of line.
LRC0009EmptyTimestamp
Warning
Literal [] group.
Group dropped; subsequent timestamps still parsed.
Encoding
Code
Severity
Trigger
Recovery
LRC0010EncodingFallback
Error
BOM detection failed and bytes are not valid UTF-8 — the configured FallbackEncoding was used.
Falls back; result still produced. The Error severity is intentional — fallback should be a conscious choice.
Metadata
Code
Severity
Trigger
Recovery
LRC0020ConflictingMetadata
Warning
Same key encountered twice with different values.
Last-wins on the typed accessor; both entries kept in RawTags.
LRC0021DuplicateMetadata
Info
Same key encountered twice with the same value.
Kept once on the typed accessor; both entries in RawTags.
Timestamp variants (tolerant accept)
The parser accepts these non-canonical forms; each emits an Info diagnostic so callers
can detect them if they care.
The parser recognises Walaoke M: / F: / D: prefixes and propagates voice state across
lines. There are no diagnostics emitted by the voice path today — unrecognised
prefixes are simply treated as line text.
Lyric flow
Code
Severity
Trigger
Recovery
LRC0050DroppedUntimedText
Info
Free text on a line with no timestamp.
Text dropped from Lines.
LRC0051TimestampWithoutText
Warning
Timestamp followed only by line terminator.
Empty Text line still emitted.
LRC0060LinesReordered
Info
Lines were not in monotonic timestamp order; output sorted.
Subsequent diagnostics suppressed. Set MaxDiagnostics = 0 to suppress everything (including this notice).
Recipes
Suppress all diagnostics
var quiet = new LrcParseOptions { MaxDiagnostics = 0 };
var result = LrcParser.Parse(text, quiet);
result.Diagnostics.Length.ShouldBe(0);
Strict mode still throws on Error-severity codes even when the cap suppresses
the diagnostic body.
Strict-mode error handling
var strict = new LrcParseOptions { Strictness = LrcStrictness.Strict };
try
{
var result = LrcParser.Parse(text, strict);
}
catch (LrcParseException ex)
{
Console.WriteLine($"{ex.FirstError?.Code} at L{ex.FirstError?.Line}");
// ex.PartialResult holds whatever was parsed before the failure
}
Triage Error / Warning / Info
var byTier = result.Diagnostics
.GroupBy(d => d.Severity)
.ToDictionary(g => g.Key, g => g.Count());