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.

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)

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.