spectreconsole/spectre.console · error · InvalidOperationException

Failed to read input in non-interactive mode.

Error message

Failed to read input in non-interactive mode.

What it means

Thrown by DefaultInput.IsKeyAvailable() when the console profile's Capabilities.Interactive is false. Spectre.Console checks the profile's interactive flag (set by terminal detection or explicit configuration) before touching System.Console.KeyAvailable. In non-interactive environments (CI, redirected stdin, headless services), reading key state is meaningless and would throw at the BCL level, so Spectre pre-empts with this InvalidOperationException.

Source

Thrown at src/Spectre.Console/Internal/DefaultInput.cs:16

namespace Spectre.Console;

internal sealed class DefaultInput : IAnsiConsoleInput
{
    private readonly Profile _profile;

    public DefaultInput(Profile profile)
    {
        _profile = profile ?? throw new ArgumentNullException(nameof(profile));
    }

    public bool IsKeyAvailable()
    {
        if (!_profile.Capabilities.Interactive)
        {
            throw new InvalidOperationException("Failed to read input in non-interactive mode.");
        }

        return System.Console.KeyAvailable;
    }

    public ConsoleKeyInfo? ReadKey(bool intercept)
    {
        if (!_profile.Capabilities.Interactive)
        {
            throw new InvalidOperationException("Failed to read input in non-interactive mode.");
        }

        return System.Console.ReadKey(intercept);
    }

    public async Task<ConsoleKeyInfo?> ReadKeyAsync(bool intercept, CancellationToken cancellationToken)
    {
        if (!_profile.Capabilities.Interactive)

View on GitHub (pinned to 0acc92fada)

Solutions

  1. Guard with AnsiConsole.Profile.Capabilities.Interactive before calling input methods.
  2. In CI or tests, use AnsiConsole.Testing's TestConsole or mock IAnsiConsoleInput rather than real input.
  3. Redirect only stdout while keeping stdin as a TTY, or run in a pseudo-terminal (e.g., script, expect) for interactive tests.
  4. If using AnsiConsole.Create, pass a Profile with Capabilities.Interactive = true when you know a real TTY is attached.

Example fix

// before
if (AnsiConsole.Input.IsKeyAvailable()) { ... }

// after
if (AnsiConsole.Profile.Capabilities.Interactive && AnsiConsole.Input.IsKeyAvailable())
{
    // safe to read keys
}
Defensive patterns

Strategy: validation

Validate before calling

if (!AnsiConsole.Profile.Capabilities.Interactive)
{
    throw new InvalidOperationException(
        "Cannot check for key availability in a non-interactive environment.");
}
bool available = AnsiConsole.Input.IsKeyAvailable();

Type guard

static bool IsInteractiveConsole(IAnsiConsole console)
    => console.Profile.Capabilities.Interactive;

Prevention

When it happens

Trigger: Calling AnsiConsole.Input.IsKeyAvailable() (or code that calls it, like prompt internals) when the console is running non-interactively — e.g., stdin is redirected, running under CI/build agents, or using AnsiConsole.Create with a non-interactive IAnsiConsoleOutput.

Common situations: Running Spectre.Console prompts or input-reading code in CI pipelines (GitHub Actions, Azure DevOps); unit tests that use AnsiConsole.Testing or a TestConsole without interactive capabilities; Docker/headless deployment where stdin is not a TTY; output redirected to a file or pipe.

Related errors


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