d2phap/ImageGlass · warning · ArgumentException

Button ID required.

Error message

Button ID required.

What it means

Thrown in FrmSettings (Tab Toolbar handler) when a custom toolbar button JSON is parsed and btn.Type == ToolbarItemModelType.Button but btn.Id is null, empty, or whitespace. It is an ArgumentException with paramName 'btn.Id'; the message comes from the localized resource FrmSettings.Toolbar._Errors._ButtonIdRequired. The handler is invoked for the Web2 messages 'Btn_AddCustomToolbarButton_ValidateJson_Create' and '..._Edit', and the resulting exception is caught and shown to the user via Config.ShowError.

Source

Thrown at v9/ImageGlass/FrmSettings.cs:245

            Web2.PostWeb2Message(e.Name, json);
        }
        else if (e.Name.Equals("Btn_AddCustomToolbarButton_ValidateJson_Create", StringComparison.Ordinal)
            || e.Name.Equals("Btn_AddCustomToolbarButton_ValidateJson_Edit", StringComparison.Ordinal))
        {
            var isCreate = e.Name.Equals("Btn_AddCustomToolbarButton_ValidateJson_Create", StringComparison.Ordinal);
            var isValid = true;

            try
            {
                // try parsing the json
                var btn = BHelper.ParseJson<ToolbarItemModel>(e.Data);

                if (btn.Type == ToolbarItemModelType.Button)
                {
                    var langPath = $"{nameof(FrmSettings)}.Toolbar._Errors";
                    if (string.IsNullOrWhiteSpace(btn.Id))
                    {
                        throw new ArgumentException(Config.Language[$"{langPath}._ButtonIdRequired"], nameof(btn.Id));
                    }

                    if (isCreate
                        && Config.ToolbarButtons.Any(i => i.Id.Equals(btn.Id, StringComparison.OrdinalIgnoreCase)))
                    {
                        throw new ArgumentException(ZString.Format(Config.Language[$"{langPath}._ButtonIdDuplicated"], btn.Id), nameof(btn.Id));
                    }

                    if (string.IsNullOrEmpty(btn.OnClick.Executable))
                    {
                        throw new ArgumentException(Config.Language[$"{langPath}._ButtonExecutableRequired"], nameof(btn.OnClick.Executable));
                    }
                }
            }
            catch (Exception ex)
            {
                _ = Config.ShowError(this, title: Config.Language["_._Error"], heading: ex.Message);
                isValid = false;

View on GitHub (pinned to 4a3c4fecef)

Solutions

  1. Provide a non-empty, unique Id in the ToolbarItemModel JSON before submitting.
  2. Add client-side validation in the Web2 toolbar form so the submit button is disabled until Id is non-blank.
  3. If building the model in C#, set btn.Id to a stable slug before validation runs.
  4. Use the default button template and only override Id rather than authoring the whole object from scratch.

Example fix

// before
var btn = new ToolbarItemModel
{
    Type = ToolbarItemModelType.Button,
    // Id missing
    OnClick = new ToolbarClickAction { Executable = "notepad.exe" },
};

// after
var btn = new ToolbarItemModel
{
    Type = ToolbarItemModelType.Button,
    Id = "open-notepad",               // required, must be unique
    OnClick = new ToolbarClickAction { Executable = "notepad.exe" },
};
Defensive patterns

Strategy: validation

Validate before calling

// Validate the parsed model before the settings handler ever throws
static bool IsValidButton(ToolbarItemModel btn, out string error)
{
    error = null;
    if (btn == null) { error = "No button payload."; return false; }
    if (btn.Type != ToolbarItemModelType.Button) return true;
    if (string.IsNullOrWhiteSpace(btn.Id))
    {
        error = "Button ID is required.";
        return false;
    }
    return true;
}

Type guard

static bool IsCompleteButton(ToolbarItemModel btn) =>
    btn != null
    && btn.Type == ToolbarItemModelType.Button
    && !string.IsNullOrWhiteSpace(btn.Id);

Try / catch

try
{
    var btn = BHelper.ParseJson<ToolbarItemModel>(e.Data);
    // ...validation...
}
catch (ArgumentException ex) when (ex.ParamName == "btn.Id")
{
    // The handler already surfaces this via Config.ShowError; treat as non-fatal form error.
    isValid = false;
}

Prevention

When it happens

Trigger: The settings Web2 UI submits a ToolbarItemModel JSON with Type 'Button' and a missing/blank Id; the JSON is created by hand or by a faulty template that omits the Id field; or the field is present but empty/whitespace.

Common situations: A user pastes a hand-written toolbar button config without an Id; a migration/import drops the Id; or the front-end form lets the submit through without client-side validation of the Id field.

Related errors


AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13). Data as JSON: /api/errors/9d58ba2db766e444. Report an issue: GitHub.