{"record":{"id":"13e1adab008c5b4c","repo":"d2phap/ImageGlass","slug":"button-executable-required","errorCode":null,"errorMessage":"Button executable required.","messagePattern":"Button executable required\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"warning","filePath":"v9/ImageGlass/FrmSettings.cs","lineNumber":256,"sourceCode":"                var btn = BHelper.ParseJson<ToolbarItemModel>(e.Data);\n\n                if (btn.Type == ToolbarItemModelType.Button)\n                {\n                    var langPath = $\"{nameof(FrmSettings)}.Toolbar._Errors\";\n                    if (string.IsNullOrWhiteSpace(btn.Id))\n                    {\n                        throw new ArgumentException(Config.Language[$\"{langPath}._ButtonIdRequired\"], nameof(btn.Id));\n                    }\n\n                    if (isCreate\n                        && Config.ToolbarButtons.Any(i => i.Id.Equals(btn.Id, StringComparison.OrdinalIgnoreCase)))\n                    {\n                        throw new ArgumentException(ZString.Format(Config.Language[$\"{langPath}._ButtonIdDuplicated\"], btn.Id), nameof(btn.Id));\n                    }\n\n                    if (string.IsNullOrEmpty(btn.OnClick.Executable))\n                    {\n                        throw new ArgumentException(Config.Language[$\"{langPath}._ButtonExecutableRequired\"], nameof(btn.OnClick.Executable));\n                    }\n                }\n            }\n            catch (Exception ex)\n            {\n                _ = Config.ShowError(this, title: Config.Language[\"_._Error\"], heading: ex.Message);\n                isValid = false;\n            }\n\n            Web2.PostWeb2Message(e.Name, BHelper.ToJson(isValid));\n        }\n        #endregion // Tab Toolbar\n\n\n        // Tab File type associations\n        #region Tab File type associations\n        else if (e.Name.Equals(\"Btn_OpenExtIconFolder\", StringComparison.Ordinal))\n        {","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/v9/ImageGlass/FrmSettings.cs#L238-L274","documentation":"Thrown in FrmSettings (Tab Toolbar handler) when a parsed ToolbarItemModel has Type 'Button' but btn.OnClick.Executable is null or empty. It is an ArgumentException with paramName 'btn.OnClick.Executable'; the message comes from the localized resource FrmSettings.Toolbar._Errors._ButtonExecutableRequired. The exception is caught by the surrounding try/catch and shown via Config.ShowError.","triggerScenarios":"The Web2 create/edit toolbar message submits a button whose OnClick object has no Executable (e.g. only Arguments or WorkingDirectory are set); the OnClick object is omitted from the JSON so Executable defaults to empty; or the executable path string is blank.","commonSituations":"A user configures arguments/working directory but forgets the program path; a template ships with OnClick partially populated; or the front-end form validates the Id but not the Executable field.","solutions":["Set btn.OnClick.Executable to the full path of the program to launch before submitting.","Add client-side validation so submit is disabled until the Executable field is non-empty.","When cloning an existing button, copy the Executable field across rather than leaving OnClick default-constructed.","Resolve the path against PATH or %ProgramFiles% and confirm the file exists before submit."],"exampleFix":"// before\nvar btn = new ToolbarItemModel\n{\n    Type = ToolbarItemModelType.Button,\n    Id = \"open-notepad\",\n    OnClick = new ToolbarClickAction { Arguments = \"%1\" }, // Executable missing\n};\n\n// after\nvar btn = new ToolbarItemModel\n{\n    Type = ToolbarItemModelType.Button,\n    Id = \"open-notepad\",\n    OnClick = new ToolbarClickAction { Executable = @\"C:\\Windows\\System32\\notepad.exe\", Arguments = \"%1\" },\n};","handlingStrategy":"validation","validationCode":"// Ensure the OnClick executable is set before submission\nstatic bool HasExecutable(ToolbarItemModel btn, out string error)\n{\n    error = null;\n    if (btn?.Type != ToolbarItemModelType.Button) return true;\n    if (btn.OnClick == null || string.IsNullOrEmpty(btn.OnClick.Executable))\n    {\n        error = \"Button executable is required.\";\n        return false;\n    }\n    return true;\n}","typeGuard":"static bool IsCompleteButton(ToolbarItemModel btn) =>\n    btn != null\n    && btn.Type == ToolbarItemModelType.Button\n    && !string.IsNullOrWhiteSpace(btn.Id)\n    && btn.OnClick != null\n    && !string.IsNullOrEmpty(btn.OnClick.Executable);","tryCatchPattern":"try\n{\n    var btn = BHelper.ParseJson<ToolbarItemModel>(e.Data);\n    // ...validation...\n}\ncatch (ArgumentException ex) when (ex.ParamName == \"btn.OnClick.Executable\")\n{\n    // Already shown via Config.ShowError; mark the form invalid.\n    isValid = false;\n}","preventionTips":["Require the Executable field in the Web2 form before submit.","When cloning a button, always copy OnClick.Executable across.","Resolve the executable path against PATH/%ProgramFiles% and confirm the file exists before submit.","Validate the full model in C# first so a single error message lists every missing field."],"tags":["toolbar","validation","settings","winforms","web2","csharp"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}