{"record":{"id":"196f997edb273733","repo":"Flow-Launcher/Flow.Launcher","slug":"unable-to-load-settings-for-plugin-pluginpair-me","errorCode":null,"errorMessage":"Unable to load settings for plugin: {pluginPair.Metadata.Name}","messagePattern":"Unable to load settings for plugin: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Flow.Launcher/PluginSettingsWindow.xaml.cs","lineNumber":37,"sourceCode":"    {\n        _settings = Ioc.Default.GetRequiredService<Settings>();\n\n        if (string.IsNullOrWhiteSpace(pluginId)){\n            throw new ArgumentException(\"Plugin ID cannot be null or whitespace.\", nameof(pluginId));\n        }\n\n        PluginId = pluginId;\n\n        var pluginPair = PluginManager.GetPluginForId(pluginId);\n        if (pluginPair == null)\n        {\n            throw new InvalidOperationException($\"Unable to find plugin: {pluginId}\");\n        }\n\n        var pluginSettings = _settings.PluginSettings.GetPluginSettings(pluginId);\n        if (pluginSettings == null)\n        {\n            throw new InvalidOperationException($\"Unable to load settings for plugin: {pluginPair.Metadata.Name}\");\n        }\n\n        var pluginViewModel = new PluginViewModel\n        {\n            PluginPair = pluginPair,\n            PluginSettingsObject = pluginSettings,\n            IsExpanded = true,\n        };\n\n        DataContext = pluginViewModel;\n        Title = Localize.pluginSettingsWindowTitle(pluginPair.Metadata.Name);\n        InitializeComponent();\n    }\n\n    // This is used for Priority control to force its value to be 0 when the user clears the value.\n    private void NumberBox_OnValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args)\n    {\n        if (double.IsNaN(args.NewValue))","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/Flow-Launcher/Flow.Launcher/blob/7fc63b07bbaa10a0f0b2601487913fcba9ed24b0/Flow.Launcher/PluginSettingsWindow.xaml.cs#L19-L55","documentation":"Thrown by the PluginSettingsWindow constructor when _settings.PluginSettings.GetPluginSettings(pluginId) returns null even though the plugin itself is loaded. The plugin was found (so error 28 did not fire) but no settings object was registered for it. This typically means the plugin has no settings schema, its settings JSON could not be deserialised, or the registration step was skipped during plugin load.","triggerScenarios":"The plugin's settings file is missing or empty (first run after install), the JSON is malformed and deserialisation silently produced null, the plugin does not implement a settings class but the UI still tries to edit it, or a plugin upgrade changed the settings type so the old payload no longer maps.","commonSituations":"Fresh install of a plugin whose settings file is created lazily; user manually deleted the plugin's Settings/*.json; plugin version bump renamed the settings class so the old JSON deserialises to null; the plugin declares PluginSettings but did not register it with PluginSettings during LoadPlugin.","solutions":["Make GetPluginSettings return a default empty settings object instead of null so the UI can always open.","Validate the settings file existence/JSON before opening the window and offer to reset on corruption.","Catch the InvalidOperationException at the caller and show a recovery dialog (reset settings).","Log the deserialisation error with the pluginId and the JSON path so failures are not silent."],"exampleFix":"// before\nvar pluginSettings = _settings.PluginSettings.GetPluginSettings(pluginId);\nif (pluginSettings == null)\n{\n    throw new InvalidOperationException($\"Unable to load settings for plugin: {pluginPair.Metadata.Name}\");\n}\n\n// after - recover with a fresh default instead of throwing\nvar pluginSettings = _settings.PluginSettings.GetPluginSettings(pluginId)\n    ?? _settings.PluginSettings.ResetPluginSettings(pluginId);","handlingStrategy":"fallback","validationCode":"var settingsFile = Path.Combine(pluginDir, pluginId, \"Settings\", \"plugin.json\");\nif (!File.Exists(settingsFile)) logger.Warn($\"Settings file missing for {pluginId}\");","typeGuard":"static bool HasSettingsRegistered(string pluginId) => Ioc.Default.GetRequiredService<Settings>().PluginSettings.GetPluginSettings(pluginId) is not null;","tryCatchPattern":"try { new PluginSettingsWindow(pluginId).Show(); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Unable to load settings\"))\n{\n    if (App.API.ShowMsg(\"Settings are corrupt. Reset?\", \"Yes\")) _settings.PluginSettings.ResetPluginSettings(pluginId);\n}","preventionTips":["Have GetPluginSettings return a default object instead of null.","Validate the settings JSON before opening the window.","Catch the exception and offer a reset.","Log deserialisation errors with the plugin ID and file path."],"tags":["plugin-manager","settings-window","deserialization","wpf","csharp"],"backgroundTag":null,"analyzedSha":"7fc63b07bbaa10a0f0b2601487913fcba9ed24b0","analyzedAt":"2026-08-13T14:54:20.914Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}