PrismLibrary/Prism · error · ArgumentException

At least one button needs to be supplied

Error message

At least one button needs to be supplied

What it means

PageDialogService.DisplayActionSheetAsync validates that at least one non-null IActionSheetButton was supplied. If the buttons array is null or all entries are null, it throws an ArgumentException naming the buttons parameter, because an action sheet with no actions is meaningless.

Solutions

  1. Ensure you pass at least one button via IActionSheetButton.FromAction / FromCancel / FromDestroy.
  2. Guard dynamic button lists: if the computed list is empty, show an alert instead or add a default cancel button.
  3. Filter out null buttons before calling, and short-circuit if nothing remains.
  4. Check that factory calls like IActionSheetButton.FromAction(...) are not themselves returning null due to overloads.

Example fix

// before
await _dialogs.DisplayActionSheetAsync("Options", FlowDirection.MatchParent, buttons);
// after
if (buttons is { Length: > 0 })
    await _dialogs.DisplayActionSheetAsync("Options", FlowDirection.MatchParent, buttons);
else
    await _dialogs.DisplayActionSheetAsync("No options available", FlowDirection.MatchParent,
        IActionSheetButton.CancelButton(() => { }));
Defensive patterns

Strategy: validation

Validate before calling

bool hasButtons = buttons is { Length: > 0 } && buttons.Any(b => b != null);
if (!hasButtons) throw new ArgumentException("At least one button required");

Type guard

static bool HasActionSheetButtons(IActionSheetButton[]? b) =>
    b is { Length: > 0 } && b.Any(x => x is not null);

Try / catch

try
{
    await _dialogs.DisplayActionSheetAsync(title, FlowDirection.MatchParent, buttons);
}
catch (ArgumentException)
{
    await _dialogs.DisplayAlertAsync(title, message, "OK");
}

Prevention

When it happens

Trigger: Calling DisplayActionSheetAsync(title, flowDirection, (IActionSheetButton[])null) or passing buttons built from an empty/dynamic list where every entry ended up null (e.g. FromAction/FromCancel constructed from null delegates or empty collections).

Common situations: Building action sheet buttons conditionally from a list that turned out empty; spreading an array with all-null elements; passing a params array variable that was never initialized.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/d3246636413307e6. Report an issue: GitHub.

Appendix: source

Thrown at src/Maui/Prism.Maui/Services/PageDialogs/PageDialogService.cs:150

    {
        await DisplayActionSheetAsync(title, FlowDirection.MatchParent, buttons);
    }

    /// <summary>
    /// Displays a native platform action sheet, allowing the application user to choose from several buttons.
    /// </summary>
    /// <para>
    /// The text displayed in the action sheet will be the value for <see cref="IActionSheetButton.Text"/> and when pressed
    /// the callback action will be executed.
    /// </para>
    /// <param name="title">Text to display in action sheet</param>
    /// <param name="flowDirection">The Text flow direction.</param>
    /// <param name="buttons">Buttons displayed in action sheet</param>
    /// <returns></returns>
    public virtual async Task DisplayActionSheetAsync(string title, FlowDirection flowDirection, params IActionSheetButton[] buttons)
    {
        if (buttons == null || buttons.All(b => b == null))
            throw new ArgumentException("At least one button needs to be supplied", nameof(buttons));

        var destroyButton = buttons.FirstOrDefault(button => button != null && button.IsDestroy);
        var cancelButton = buttons.FirstOrDefault(button => button != null && button.IsCancel);
        var otherButtonsText = buttons.Where(button => button != null && !(button.IsDestroy || button.IsCancel)).Select(b => b.Text).ToArray();

        var pressedButton = await DisplayActionSheetAsync(title, cancelButton?.Text, destroyButton?.Text, flowDirection, otherButtonsText);

        foreach (var button in buttons.Where(button => button != null && button.Text.Equals(pressedButton)))
        {
            await button.PressButton();
            return;
        }
    }

    /// <summary>
    /// Displays a native platform prompt, allowing the application user to enter a string.
    /// </summary>
    /// <param name="title">Title to display</param>

View on GitHub (pinned to 358118cd64)