tui-cs/Terminal.Gui · error · JsonException
Configuration JSON root must not be null.
Error message
Configuration JSON root must not be null.
What it means
Thrown by SourcesManager.Load(Stream,...) when JsonSerializer.Deserialize returns null for the SettingsScope root — meaning the JSON document's root token was the literal 'null'. Terminal.Gui requires a JSON object as the configuration root. Note: this JsonException is caught immediately after (SourcesManager.cs:177) and only re-thrown if ConfigurationManager.ThrowOnJsonErrors is true (default false); otherwise it is recorded via ConfigurationManager.AddJsonError and printed at Application shutdown.
Source
Thrown at Terminal.Gui/Configuration/SourcesManager.cs:163
{
if (settingsScope is null)
{
return false;
}
// Update the existing settings with the new settings.
try
{
#if DEBUG
string? json = new StreamReader (stream).ReadToEnd ();
stream.Position = 0;
Debug.Assert (json != null);
#endif
SettingsScope? scope = JsonSerializer.Deserialize (stream, TuiSerializerContext.Instance.SettingsScope);
if (scope is null)
{
throw new JsonException ("Configuration JSON root must not be null.");
}
settingsScope.UpdateFrom (scope);
ConfigurationManager.OnUpdated ();
AddSource (location, source);
Logging.Trace ($"Read configuration from \"{source}\" - ConfigLocation: {location}");
Trace.Configuration (source, "Load", $"location={location}");
return true;
}
catch (JsonException e)
{
if (ConfigurationManager.ThrowOnJsonErrors ?? false)
{
throw;View on GitHub (pinned to 2e47b11478)
Solutions
- Replace the file contents with a valid JSON object (at minimum '{}') or delete the file so Terminal.Gui falls back to defaults.
- Set ConfigurationManager.ThrowOnJsonErrors = false (the default) so a bad file is logged but does not crash startup, then fix the file.
- If it comes from TUI_CONFIG, unset the env var or point it at a valid JSON object.
Example fix
// before: .tui/config.json
null
// after: .tui/config.json
{
"Theme": "Default"
} Defensive patterns
Strategy: validation
Validate before calling
// Reject a 'null' root before handing the stream to Terminal.Gui
using JsonDocument doc = JsonDocument.Parse (stream);
stream.Position = 0;
if (doc.RootElement.ValueKind == JsonValueKind.Null)
throw new InvalidOperationException ("Config root is the literal null; replace with an object."); Type guard
static bool IsConfigRootValid (Stream s)
{ s.Position = 0; try { using var d = JsonDocument.Parse (s); return d.RootElement.ValueKind == JsonValueKind.Object; } catch { return false; } finally { s.Position = 0; } } Try / catch
ConfigurationManager.ThrowOnJsonErrors = false; // default; logs instead of throwing
try { /* load */ } catch (JsonException ex) when (ex.Message.Contains ("must not be null")) { /* handle */ } Prevention
- Treat config files as code: review them and lint them in CI.
- Write config files atomically and never write the literal 'null'.
- Set ThrowOnJsonErrors = false in production so a malformed file logs rather than crashes.
When it happens
Trigger: A config file (.tui/config.json, <App>.config.json, a TUI_CONFIG-pointed file, or an embedded resource) whose entire contents are the four bytes 'null'. Also possible if a custom RuntimeConfig string is set to "null".
Common situations: A tool or script wrote the literal string "null" into the config file; a previous failed write left a placeholder; a user typed 'null' thinking it clears settings.
Related errors
- Unexpected StartObject token when parsing Attribute: {reader
- {propertyName}: Both Foreground and Background colors must b
- {value}: Invalid Rune. The second codepoint is not valid: {s
- {value}: Invalid Rune. The second codepoint is not a combini
- {value}: Invalid combined Rune.
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/6e92b02d90d3b9f8.
Report an issue: GitHub.