spectreconsole/spectre.console · error · InvalidOperationException
Invalid JSON
Error message
Invalid JSON
What it means
JsonParser.Shared.Parse(string) tokenizes and reads JSON; any exception from the tokenizer or reader is swallowed and re-thrown as a bare InvalidOperationException("Invalid JSON") with no inner exception, so the original cause (unexpected token, trailing comma, unterminated string) is lost.
Source
Thrown at src/Extensions/Spectre.Console.Json/JsonParser.cs:17
namespace Spectre.Console.Json;
internal sealed class JsonParser : IJsonParser
{
public static JsonParser Shared { get; } = new JsonParser();
public JsonSyntax Parse(string json)
{
try
{
var tokens = JsonTokenizer.Tokenize(json);
var reader = new JsonTokenReader(tokens);
return ParseElement(reader);
}
catch
{
throw new InvalidOperationException("Invalid JSON");
}
}
private static JsonSyntax ParseElement(JsonTokenReader reader)
{
return ParseValue(reader);
}
private static List<JsonSyntax> ParseElements(JsonTokenReader reader)
{
var members = new List<JsonSyntax>();
while (!reader.Eof)
{
members.Add(ParseElement(reader));
if (reader.Peek()?.Type != JsonTokenType.Comma)
{View on GitHub (pinned to 0acc92fada)
Solutions
- Validate/parse the JSON with System.Text.Json.JsonDocument.Parse first to get a precise error location
- Wrap the call in try/catch and log the raw input plus its length for diagnosis
- Fix the source JSON (close braces, quote keys, remove trailing commas)
- If you control input generation, round-trip it through a strict serializer before storing
Example fix
// before
var syntax = JsonParser.Shared.Parse(maybeBrokenJson);
// after (pre-validate to surface the real error)
try
{
using var doc = JsonDocument.Parse(maybeBrokenJson);
}
catch (JsonException ex)
{
throw new InvalidOperationException($"Input is not valid JSON at line {ex.LineNumber}, pos {ex.BytePositionInLine}.", ex);
}
var syntax = JsonParser.Shared.Parse(maybeBrokenJson); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate JSON with the runtime serializer to get a precise error:
public static bool IsValidJson(string input)
{
try { using var _ = JsonDocument.Parse(input); return true; }
catch (JsonException) { return false; }
} Try / catch
try
{
var syntax = JsonParser.Shared.Parse(json);
}
catch (InvalidOperationException ex) when (ex.Message == "Invalid JSON")
{
// Log raw input + length; the library discards the inner cause,
// so fall back to JsonDocument.Parse for diagnostics if needed.
logger.LogWarning("Rejected malformed JSON (len={Len}).", json.Length);
} Prevention
- Never feed unvalidated external text to JsonParser.Shared.Parse
- Pre-parse with System.Text.Json to surface line/position of the real error
- Keep JSON sources machine-generated via a strict serializer
When it happens
Trigger: Calling JsonParser.Shared.Parse(json) (or any code path that uses it) with a malformed JSON string: unbalanced braces, trailing commas, unquoted keys, truncated input, or BOM/encoding artifacts.
Common situations: Feeding user-supplied or file-loaded JSON without pre-validation; a config file edited by hand with a syntax error; an upstream service changed its payload format; copy-paste that dropped a closing brace.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Encountered closing tag when none was expected near position
- Encountered unknown markup token.
- Unbalanced markup stack. Did you forget to close a tag?
- Encountered unescaped ']' token at position {_reader.Positio
- Encountered malformed markup tag at position {pos}.
AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13).
Data as JSON: /api/errors/ba4e1c3fca8846f4.
Report an issue: GitHub.