spectreconsole/spectre.console · error · InvalidOperationException

At least one column must be specified.

Error message

At least one column must be specified.

What it means

Thrown by the Progress.Columns(this Progress, params ProgressColumn[]) extension method when the columns array is empty. Progress requires at least one column to render anything meaningful (e.g., TaskDescriptionColumn, ProgressBarColumn, PercentageColumn). Calling Columns() with no arguments produces a zero-length array via params, triggering the !columns.Any() guard.

Solutions

  1. Pass at least one ProgressColumn, e.g., .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()).
  2. If building columns dynamically, ensure the collection is non-empty before calling Columns.
  3. Default to the built-in column set and only override when you have at least one column.

Example fix

// before
var progress = AnsiConsole.Progress().Columns();

// after
var progress = AnsiConsole.Progress()
    .Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn());
Defensive patterns

Strategy: validation

Validate before calling

// Ensure at least one column
var columns = BuildColumns();
if (columns.Length == 0)
{
    columns = new ProgressColumn[]
    {
        new TaskDescriptionColumn(),
        new ProgressBarColumn(),
        new PercentageColumn(),
    };
}
AnsiConsole.Progress().Columns(columns);

Type guard

static bool HasAtLeastOneColumn(ProgressColumn[] columns)
    => columns is { Length: > 0 };

Prevention

When it happens

Trigger: Calling AnsiConsole.Progress().Columns() with no arguments, or calling .Columns(someArray) where someArray is empty. This can also happen if columns are conditionally filtered out before being passed.

Common situations: Dynamically building the columns list from configuration and passing an empty list; refactoring that accidentally removes all column arguments; calling Columns() in a fluent chain where the params overload is invoked with zero args by mistake.

Related errors


AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13). Data as JSON: /api/errors/ed42e465a685ed48. Report an issue: GitHub.

Appendix: source

Thrown at src/Spectre.Console/Live/Progress/Progress.cs:198

/// Contains extension methods for <see cref="Progress"/>.
/// </summary>
public static class ProgressExtensions
{
    /// <summary>
    /// Sets the columns to be used for an <see cref="Progress"/> instance.
    /// </summary>
    /// <param name="progress">The <see cref="Progress"/> instance.</param>
    /// <param name="columns">The columns to use.</param>
    /// <returns>The same instance so that multiple calls can be chained.</returns>
    public static Progress Columns(this Progress progress, params ProgressColumn[] columns)
    {
        ArgumentNullException.ThrowIfNull(progress);

        ArgumentNullException.ThrowIfNull(columns);

        if (!columns.Any())
        {
            throw new InvalidOperationException("At least one column must be specified.");
        }

        progress.Columns.Clear();
        progress.Columns.AddRange(columns);

        return progress;
    }

    /// <summary>
    /// Sets an optional hook to intercept rendering.
    /// </summary>
    /// <param name="progress">The <see cref="Progress"/> instance.</param>
    /// <param name="renderHook">The custom render function.</param>
    /// <returns>The same instance so that multiple calls can be chained.</returns>
    public static Progress UseRenderHook(this Progress progress, Func<IRenderable, IReadOnlyList<ProgressTask>, IRenderable> renderHook)
    {
        progress.RenderHook = renderHook;

View on GitHub (pinned to 0acc92fada)