tui-cs/Terminal.Gui · error · InvalidOperationException

Themes must include an item named {DEFAULT_THEME_NAME}

Error message

Themes must include an item named {DEFAULT_THEME_NAME}

What it means

Thrown by ThemeManager.SetThemes when the dictionary being assigned to the Themes property is non-null but does not contain the key "Default" (ThemeManager.DEFAULT_THEME_NAME). Terminal.Gui requires a Default theme to always exist because Theme getter, LoadHardCodedDefaults, and UpdateToCurrentValues all assume Themes[Theme] resolves and Theme defaults to "Default".

Source

Thrown at Terminal.Gui/Configuration/ThemeManager.cs:135

    [JsonConverter (typeof (ConcurrentDictionaryJsonConverter<ThemeScope>))]
    [ConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
    public static ConcurrentDictionary<string, ThemeScope>? Themes
    {
        // Note: This property getter must be public; DeepClone depends on it.
        get => GetThemes ();
        internal set => SetThemes (value);
    }

    /// <summary>
    ///     INTERNAL: Setter for <see cref="Themes"/>.
    /// </summary>
    /// <param name="dictionary"></param>
    /// <exception cref="InvalidOperationException"></exception>
    private static void SetThemes (ConcurrentDictionary<string, ThemeScope>? dictionary)
    {
        if (dictionary is { } && !dictionary.ContainsKey (DEFAULT_THEME_NAME))
        {
            throw new InvalidOperationException ($"Themes must include an item named {DEFAULT_THEME_NAME}");
        }

        if (ConfigurationManager.Settings is { } && ConfigurationManager.Settings.TryGetValue ("Themes", out ConfigProperty? themes))
        {
            ConfigurationManager.Settings ["Themes"].PropertyValue = dictionary;

            return;
        }

        throw new InvalidOperationException ("Settings is null.");
    }

    /// <summary>
    ///     INTERNAL: Returns the hard-coded Themes dictionary.
    /// </summary>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    private static ConcurrentDictionary<string, ThemeScope>? GetHardCodedThemes ()

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Ensure the dictionary contains a "Default" key (case-insensitive, StringComparer.InvariantCultureIgnoreCase is used internally) before assigning.
  2. Build the dictionary from GetHardCodedThemes() and then add/override entries rather than starting from an empty one.
  3. If loading from JSON, keep the "Default" theme block intact in the config file.

Example fix

// before
ThemeManager.Themes = new ConcurrentDictionary<string, ThemeScope> (
    new Dictionary<string, ThemeScope> { ["Dark"] = darkScope });

// after
var themes = new ConcurrentDictionary<string, ThemeScope> (
    new Dictionary<string, ThemeScope> { ["Default"] = ThemeManager.GetHardCodedThemes()!["Default"] },
    StringComparer.InvariantCultureIgnoreCase);
themes ["Dark"] = darkScope;
ThemeManager.Themes = themes;
Defensive patterns

Strategy: validation

Validate before calling

// Ensure 'Default' is present before assigning
if (!dictionary.ContainsKey (ThemeManager.DEFAULT_THEME_NAME))
    dictionary [ThemeManager.DEFAULT_THEME_NAME] = ThemeManager.GetHardCodedThemes ()! [ThemeManager.DEFAULT_THEME_NAME];
ThemeManager.Themes = dictionary;

Type guard

static bool HasDefaultTheme (ConcurrentDictionary<string, ThemeScope> d)
    => d.ContainsKey (ThemeManager.DEFAULT_THEME_NAME);

Try / catch

try { ThemeManager.Themes = newThemes; }
catch (InvalidOperationException ex) when (ex.Message.Contains ("Default"))
{ /* add the Default entry and retry */ }

Prevention

When it happens

Trigger: Programmatically assigning ThemeManager.Themes = new ConcurrentDictionary<string,ThemeScope>(...) that lacks a "Default" entry; deserializing a themes JSON where the "Default" key was renamed or removed; setting Themes before ConfigurationManager is initialized with an incomplete dictionary.

Common situations: A user edits config.json to rename the Default theme; a fork ships a themes dictionary without preserving Default; a test sets Themes to a fixture missing the key.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/6e35df4a4bf54b4c. Report an issue: GitHub.