{"record":{"id":"6e35df4a4bf54b4c","repo":"tui-cs/Terminal.Gui","slug":"themes-must-include-an-item-named-default-theme-n","errorCode":null,"errorMessage":"Themes must include an item named {DEFAULT_THEME_NAME}","messagePattern":"Themes must include an item named (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Terminal.Gui/Configuration/ThemeManager.cs","lineNumber":135,"sourceCode":"    [JsonConverter (typeof (ConcurrentDictionaryJsonConverter<ThemeScope>))]\n    [ConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]\n    public static ConcurrentDictionary<string, ThemeScope>? Themes\n    {\n        // Note: This property getter must be public; DeepClone depends on it.\n        get => GetThemes ();\n        internal set => SetThemes (value);\n    }\n\n    /// <summary>\n    ///     INTERNAL: Setter for <see cref=\"Themes\"/>.\n    /// </summary>\n    /// <param name=\"dictionary\"></param>\n    /// <exception cref=\"InvalidOperationException\"></exception>\n    private static void SetThemes (ConcurrentDictionary<string, ThemeScope>? dictionary)\n    {\n        if (dictionary is { } && !dictionary.ContainsKey (DEFAULT_THEME_NAME))\n        {\n            throw new InvalidOperationException ($\"Themes must include an item named {DEFAULT_THEME_NAME}\");\n        }\n\n        if (ConfigurationManager.Settings is { } && ConfigurationManager.Settings.TryGetValue (\"Themes\", out ConfigProperty? themes))\n        {\n            ConfigurationManager.Settings [\"Themes\"].PropertyValue = dictionary;\n\n            return;\n        }\n\n        throw new InvalidOperationException (\"Settings is null.\");\n    }\n\n    /// <summary>\n    ///     INTERNAL: Returns the hard-coded Themes dictionary.\n    /// </summary>\n    /// <returns></returns>\n    /// <exception cref=\"InvalidOperationException\"></exception>\n    private static ConcurrentDictionary<string, ThemeScope>? GetHardCodedThemes ()","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/tui-cs/Terminal.Gui/blob/2e47b11478db083499917f2ad27c34d30efb0df1/Terminal.Gui/Configuration/ThemeManager.cs#L117-L153","documentation":"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\".","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the dictionary contains a \"Default\" key (case-insensitive, StringComparer.InvariantCultureIgnoreCase is used internally) before assigning.","Build the dictionary from GetHardCodedThemes() and then add/override entries rather than starting from an empty one.","If loading from JSON, keep the \"Default\" theme block intact in the config file."],"exampleFix":"// before\nThemeManager.Themes = new ConcurrentDictionary<string, ThemeScope> (\n    new Dictionary<string, ThemeScope> { [\"Dark\"] = darkScope });\n\n// after\nvar themes = new ConcurrentDictionary<string, ThemeScope> (\n    new Dictionary<string, ThemeScope> { [\"Default\"] = ThemeManager.GetHardCodedThemes()![\"Default\"] },\n    StringComparer.InvariantCultureIgnoreCase);\nthemes [\"Dark\"] = darkScope;\nThemeManager.Themes = themes;","handlingStrategy":"validation","validationCode":"// Ensure 'Default' is present before assigning\nif (!dictionary.ContainsKey (ThemeManager.DEFAULT_THEME_NAME))\n    dictionary [ThemeManager.DEFAULT_THEME_NAME] = ThemeManager.GetHardCodedThemes ()! [ThemeManager.DEFAULT_THEME_NAME];\nThemeManager.Themes = dictionary;","typeGuard":"static bool HasDefaultTheme (ConcurrentDictionary<string, ThemeScope> d)\n    => d.ContainsKey (ThemeManager.DEFAULT_THEME_NAME);","tryCatchPattern":"try { ThemeManager.Themes = newThemes; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains (\"Default\"))\n{ /* add the Default entry and retry */ }","preventionTips":["Always seed a new themes dictionary from GetHardCodedThemes() so Default is preserved.","Never rename or remove the \"Default\" key in config JSON.","Add a unit test asserting Themes always contains Default after any assignment."],"tags":["config","theme","theme-manager","invariant"],"backgroundTag":null,"analyzedSha":"2e47b11478db083499917f2ad27c34d30efb0df1","analyzedAt":"2026-08-13T19:20:08.826Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}